Skip to content
BetaDocs

Migration URL Tools

These tools wrap /api/v1/sites/{siteId}/migration-urls, with /import-sitemap and /import-gsc for bulk import. The same API key works over REST; see calling the same operations over REST.

When you move an existing site to Typeroll, the risk isn’t the content — it’s the URLs. Every address that Google, a bookmark or another site’s link points at has to keep working, or you lose the traffic that was already yours.

Typeroll keeps a URL inventory per site for exactly this, and the AI agent can read and write it.

“Is this site ready to receive the migration?”

The AI agent calls get_migration_readiness first. It checks the things whose absence you would otherwise discover months later:

Check Why it blocks
Media storage Without it, imported pages keep their original image URLs. The new site looks perfect and is still being served images by the old host — invisible until that hosting is cancelled, when every image breaks at once.
Publishing With verified Organization storage, customer publishing can import and preview before GitHub, builds or domains are connected. Legacy self-hosted setups may still report a missing hosting adapter. Publication readiness is checked separately.
The old site If the host refuses our requests (bot protection, an IP allowlist, HTTP auth on a staging copy), the import produces empty pages — or pages containing the block page, which reads as real content.

Warnings don’t stop the job but are worth knowing: no verification URL for the pre-cutover check, forms with no notification address, or a target site with no design for the content to be rebuilt into.

If it isn’t ready, fix the blockers before starting. The content work is the expensive part of a migration, and every blocker above means doing it twice.

They sound the same and they are not:

Question Tool
“Is every old URL accounted for in our data?” list_migration_urls
“Are saved internal links intact?” check_internal_links
“Does this exact deployment answer every variant?” verify_migration_urls
“Was content and SEO parity reviewed?” record_migration_seo_acceptance

The first classifies each inventory entry against the site’s current pages and redirects. The third requests every URL against the deployed site and reports what came back. They disagree exactly when it matters — a redirect pointing at a page that was never published, a typo in a path, a redirect loop. All of those look handled in the data and return a 404 to a visitor.

Returns the inventory with a live coverage status per entry:

  • migrated — a Page answers at that path, or the build writes it: archive pagination of a published Page with a paginated listing (/blog/page/2, marked generated: "archive_pagination") or a root file every publication writes (/favicon.ico, /robots.txt, /sitemap.xml, /sitemap-images.xml, /llms.txt, marked generated: "site_file"). Deployed URL parity still verifies that these answer.
  • redirected — a redirect rule covers it
  • excluded — you decided it should 404
  • matched_draft — a matching Page exists but is not published; this is not live coverage
  • unhandled — nothing covers it yet; this is the work list

Status is recomputed on every read, so it’s never stale: create a redirect and the entry flips on the next call.

“Show me everything from the old site that still isn’t handled.”

Populates the inventory in bulk — from the old sitemap, a Search Console export, or a crawl. Re-adding a known URL merges it rather than duplicating.

“Read https://oldsite.com/sitemap.xml and add every URL to the inventory.”

Pass Search Console click counts along with the URLs and the coverage report sorts itself: the addresses carrying real traffic rise to the top of the work list.

Migrating several sites at once? Always give the source origin. Two markets both have a /kontakt, and without the origin guard one site’s URLs can silently register as another’s coverage.

Marks an entry excluded — the record that a URL is meant to disappear. This is what distinguishes “we haven’t looked at it” from “we decided”, which is the whole value of the report.

“Exclude these private source-admin/session URLs with a reason. Keep public campaign pages working or redirect them to relevant replacement content.”

The preserve/renew migration contract requires continuity for every old public URL. The API still supports intentional retirement, but using it for public content needs a separately agreed exception; exclusion is not a shortcut to launch readiness.

Applies one patch to many inventory entries in a single request. Select entries with either ids (up to 2,000) or where: { source }, never both, and send the change as patch. Use it for migration-wide decisions, such as marking every guessed WordPress redirect URL as an intentional 404, instead of hundreds of single updates. The answer has matched, updated and unchanged counts, unknown ids and the refreshed coverage summary.

Imports per-URL clicks and impressions from Google Search Console into the inventory. Pass property (with optional months) for a direct Search Console query, or csv with an exported report as the fallback. source_origin names the old site’s origin. URL fragments are stripped, metrics for the same URL are summed, and URLs not yet in the inventory are added as unhandled. See below for what to do when Search Console denies access.

Older WordPress imports can contain encoded entities or HTML tags in fields that should be plain text. This tool decodes exactly one entity layer and removes markup, but only from title, seo_title, seo_description, and schema-defined plain-text excerpt fields. It cannot change rich content, HTML, slugs, paths, or URLs.

It defaults to a dry run and returns exact before/after diffs. Review all of them before running it again with dry_run: false. Use save: false to create working copies for portal review, or save: true to commit through the normal revision path. A resource with an existing working copy is reported as a conflict and left untouched.

“Audit legacy WordPress titles and SEO text, then show me every proposed change.”

The pre-cutover check. Requests every inventory URL against the deployed site and classifies the response:

Verdict Meaning
ok 200 at the same path — the URL was preserved
ok_redirect redirects to a page that answers
missing 404 or 410 — this URL will break
broken_redirect a loop, or a chain ending badly
error 5xx or timeout — inconclusive, run it again

A redirect rule whose from_path has a query string, such as /?p=12 or /category/news/?lang=en, is published as a small script in the page that answers its path, or in 404.html when no page does. The check reads that script and follows it, so the URL counts as ok_redirect with client_redirect: true and status showing what the server itself answered (200 or 404). Browsers and Google follow these redirects, but they are not a 301; a rule on a plain path is, so prefer one when the query adds nothing.

A timeout, network error, 429 or 5xx, including one on a later hop of a redirect, is retried up to twice more at a slower pace with a longer timeout; attempts appears only on a result that took more than one request and shows how many it took. When more than 60 URLs and more than a quarter of all URLs fail, the host is treated as down and the errors are reported without retries.

By default it tests the site’s fallback subdomain, which is the right target while your real domain still points at the old host. That’s the point: you find and fix the gaps before anything is switched over, with the old site still serving.

It also stamps verification onto the redirect rules it exercised, so you can see which ones have actually been proven to work.

“Deploy, then check every old URL against the new site and tell me what would break.”

Deploy first — the check tests published, deployed content, not unsaved drafts.

A complete, unfiltered run stores compact evidence for the launch report. It records the target origin, check time, expected request count (including slash variants), and the latest successful non-dry-run deploy job. Filtered or truncated runs never replace this evidence. One call checks at most 500 inventory URLs. For a larger inventory the response has truncated: true, evidence_stored: false and a next_step naming the url_parity workflow (start_workflow with type: "url_parity"), which checks every URL in one run and records the evidence. A complete call returns evidence_stored: true.

Records the result of a human- or tool-reviewed content/SEO comparison. It does not pretend to run that comparison. Supply the source and target origins, dataset description, checked page count, timestamp, and counts for intentional and unresolved differences. Accepted evidence requires zero unresolved differences and is bound server-side to the latest successful hosted deploy.

This is the final, fail-closed launch gate. It reports inventory coverage, exclusions without reasons, saved-link integrity, the exact hosted deployment, deployed URL parity, untested URL variants, and reviewed content/SEO parity as separate sections.

launch_ready remains false when any section is absent or failed. A new deploy also makes both URL and SEO evidence stale, even if the content appears unchanged; rerun the checks against that deployment. This prevents “zero unhandled URLs” from being mistaken for proof that a migration is safe to launch.

For a single WordPress site, the portal’s migration workflow builds the inventory for you. For anything else — a Squarespace site, a static export, or a whole family of sites moving together — the AI agent populates it with add_migration_urls and works the list down to zero.

For a multi-site or multi-domain move, ask the AI agent to read the tr-migrate-multisite skill first.

Core 0.2.5 also requires fidelity evidence for a ready launch report. record_migration_seo_acceptance accepts fidelity: { desktop, mobile, shared_data, integrations, evidence }. The four checks must be true, with a nonempty description of the chosen intent and comparison: source fidelity for preserve, approved design/content for renew. Record approved changes as intentional differences, not unresolved regressions. Review representative articles, an archive and the home page where applicable; document intentional differences. This records an actual review, not an automated visual test. Missing evidence reports fidelity_review_missing, even if HTTP and SEO checks succeeded.

get_migration_readiness accepts compositions for a read-only block/field review. Choose separate text and design/image choices in the project brief; these intent labels are not migration API parameters.

After reviewing standard-block alternatives, record an intentional custom type or exceptional HTML fragment on the composition:

{
"name": "Article with an art-directed hero",
"blocks": [],
"reviewed_custom_block_types": [
{
"type": "layered_hero",
"reason": "Responsive layered hero with editable title, image and CTA; prototype reviewed."
}
],
"reviewed_html_blocks": [
{
"block_id": "one-off-artwork",
"reason": "Unique layered hero animation; standard and custom alternatives reviewed, reduced motion and breakpoints tested."
}
]
}

Supply the actual proposed block tree instead of the empty example blocks. Each review list accepts up to 100 entries. Names/IDs and reasons must be nonempty; reasons allow up to 2,000 characters. HTML exceptions match an exact block ID, not every HTML block. The response retains them in reviewed_exceptions. Missing types, missing declared fields, unreviewed workarounds and per-instance CSS remain blockers. Reviews attest a decision; they do not establish visual quality, recursively validate custom implementations or authorize publishing. Validate custom types separately and inspect preview and static output.

Availability: these review fields require Core 0.2.89 / MCP 0.45.69. Cloud availability follows its Core rollout. Older installations do not accept them; inspect the deployed tool schema before calling. Standard block and URL verification tools are unchanged.

Available with Core 0.2.103 / MCP 0.45.79. In Migration URLs → Discover public WordPress URLs, enter the old site’s HTTPS origin. Typeroll reads public REST pages, posts and exposed custom types, then crawls at most ten pages for links. This adds evidence to the inventory; it does not import or rewrite page content.

With MCP, call import_sitemap with the sitemap url, include_wordpress: true and optionally crawl_pages: 10. REST uses the same input on /import-sitemap. The response includes discovery warnings and a truncated flag. Do not call an inventory complete when a limit, permission or access restriction prevented a full read. Public REST cannot discover private types, all old slugs or orphan URLs; combine it with historical redirects, GSC and an authoritative export.

check_internal_links reports unpublished_targets separately from broken. It also checks draft page sources (listed in draft_sources), so links can be corrected before publishing. Problems confined to unpublished source pages do not block launch of the live pages. Matched drafts still block migration launch; they do not count as migrated. Redirect writes return structured chain/loop warnings. The Redirects page and migration launch report also show these. Prefer direct final destinations, and remove loops; Typeroll never rewrites intentional redirects automatically.

If Search Console denies access, the error names the exact property and service account. Grant that account read access to that property. Domain properties and URL-prefix properties have separate permissions. Platform administrators must enable the Search Console API; self-host GCP provisioning/doctor includes it. Choose another property explicitly or import a CSV export; Typeroll does not silently substitute a different source.

A verifier denied with 401, 403 or 429 has an access problem, not evidence of a missing page. Resolve that separately. A successful probe also does not prove access for Google or any other verified crawler.