Deploy Tools
trigger_deploy
Section titled “trigger_deploy”Starts a new deploy. Returns a job_id that the AI agent uses to track progress.
Deploy the site.Ask the agent to deploy explicitly after you have reviewed and saved the intended changes.
Dry runs
Section titled “Dry runs”Pass dry_run: true to validate without publishing. Customer publishing validates
the frozen source without pushing Git or starting an external build. It also
applies validation rules that need no rendering: an image link without an
accessible name (<a><img alt=""></a> without text, or an image block with a
link and empty alt) fails the dry run with publication_validation_failed,
as the build would after media preparation. It does not prove that Astro
compilation succeeds or that the rendered pages pass every other check. Other self-hosted adapters may build
locally without uploading. Inspect the reported phase; a successful dry run has
dry_run: true and no deploy_url.
get_deploy_status
Section titled “get_deploy_status”Polls the deploy job for status. The AI agent calls this in a loop until the deploy completes or fails.
Possible statuses:
queued— waiting to startrunning— build or distribution in progresssucceeded— deployed successfullyfailed— build error (the AI agent will report what went wrong)
Partial rendering
Section titled “Partial rendering”From Core 0.2.15, generated publication builds can reuse unchanged HTML. The
optional job.render_report records actual mode (full or partial),
rendered, reused, total, removed and reason. removed counts routes in
the available cache that are absent from the current output. This is separate
from get_publication_impact, which compares source inputs before the build.
Recorded queries, visited records, references and navigation identify affected consumers, including after additions and removals. Unchanged addresses are excluded from the render queue. Missing or invalid cache falls back to full rendering. Both paths produce a complete static site with regenerated global output. See Partial builds for engine updates, independent builds and limits. These counts do not measure provider startup, media processing, upload time or billing savings.
Build cost
Section titled “Build cost”Completed jobs also carry a cost object — what the build cost the platform in
server time:
{ "cost": { "currency": "USD", "total": 0.00085336, "cpu": 0.00077249, "memory": 0.00008047, "request": 0.0000004, "duration_s": 32.187, "vcpu": 1, "memory_gib": 1, "phases": { "materializing content": 0.955, "building": 17.176, "bundling block assets": 0.201, "uploading": 6.2 }, "output_bytes": 3417900, "output_files": 80, "estimated": true }}The phases breakdown is the useful part when a site starts building slowly —
it tells you which stage is actually consuming the time.
Two caveats worth stating plainly:
- These are estimates, not billing records. They’re computed from a rate card (instance time × allocated vCPU and memory, the way a request-based container is billed), not read back from a cloud billing API. Free-tier allowances and committed-use discounts are not deducted, so the figures are gross and a real invoice comes out lower.
- Failed builds are costed too. A build that errors consumes the same server time as one that succeeds, so it gets a cost row. A site stuck in a build-failure loop should not look free.
Self-hosters can retune the rates — or set them to zero, if you run on hardware
you already pay for — with the DEPLOY_COST_* environment variables. See
Self-Hosting.
get_preview_link
Section titled “get_preview_link”Returns a signed preview URL for the current site state — without deploying. Use this to review changes before they go live.
Show me a preview of the site.The preview link is valid for 24 hours and renders saved database state, not
the last deploy. Pass include_working_copy: true when the reviewer should also
see unsaved drafts; that choice is signed into the link. Anyone holding the link
sees unpublished content, so creating one needs write permission on the site, in
the portal as well as through the API.
The preview runs in a sandbox without cookies, so a cookie banner returns on
every page. For visual review, add &consent=all to the link to answer it for
the whole session: the banner stays hidden and consented scripts and embeds
load. &consent=necessary hides the banner and loads only necessary scripts.
The sandbox itself is unchanged; a widget that needs a first-party origin may
still need a test publication.
Use the preview for content and layout review. Its page is a nested frame with an opaque origin, served from the portal, so third-party iframes often stay empty, consent choices, cookies and storage do not persist, analytics cannot be verified, fonts load from Google, and DOM or computed-style reads from a reviewing browser are limited. Verify those, and any measured design check, on the published temporary or test address.
get_page_preview
Section titled “get_page_preview”Returns one page rendered as a single HTML document in the response body
(rendered_html) together with its internal_links, without deploying. The
output matches the portal’s Preview: header and footer, settings CSS, block
CSS, block JavaScript, installed Extension components and the cookie-consent
banner are all included. Pass annotate: true to tag each block’s root element
with its block id and type, and include_working_copy: true to include unsaved
drafts. Over REST: GET /api/v1/sites/{siteId}/pages/{pageId}/preview with
?annotate=true and ?working_copy=true.
Forms in both kinds of preview run in preview mode: they validate and step through like the published form and show its success message, but store and send nothing. See Forms in previews.
read_site_readiness
Section titled “read_site_readiness”A site-level launch report built from saved content and settings. Run it before launch and after larger changes, then fix each open item or record why it stays open. It never blocks a publication and never changes content.
{ "site_id": "...", "checked_at": "2026-11-01T12:00:00.000Z", "summary": { "ok": 15, "suggestions": 3, "warnings": 2 }, "items": [ { "id": "share_image", "status": "suggestion", "message": "No default share image. Pages without their own image fall back to the logo when shared.", "fix": "Optional: upload or choose a 1200 × 630 px image, or create one with tr-imagegen, and set it as default_og_image.", "guide": "https://typeroll.com/docs/guides/launch-checklist/#share-image" } ]}status is ok, suggestion or warning. details lists up to 20 affected
pages or values. Pass version to check a branch. The same report is
available at GET /api/v1/sites/{siteId}/readiness and in the portal on the
site overview.
| Item | Checks |
|---|---|
share_image |
default_og_image is set (a suggestion when missing), and it and page og_image values are not SVG, data URLs or narrower than 600 px |
home_description |
The home page at / exists and has its own seo_description |
organization |
Organization name and logo for structured data |
same_as |
Profile links in organization.same_as or the social settings |
favicon |
A favicon is set |
analytics_consent |
Tracking scripts or Integrations tags run only with the cookie banner; a suggestion when no analytics is set up |
search_console |
A Google verification tag in scripts_head. DNS verification is not visible to Typeroll, so this stays a suggestion without one |
privacy_page, contact_page |
A published privacy page and a contact page or contact details |
not_found_page |
Always OK: every publication includes a 404 page |
indexable_pages |
sitewide_noindex is off and more than one page can be indexed |
orphan_pages |
Indexable pages that no other page, menu, template or listing links to |
duplicate_titles, duplicate_descriptions |
Titles and descriptions shared by several pages, including pages that fall back to the site description |
heading_h1 |
Each indexable page renders exactly one H1, counting the page, its template and the header and footer |
long_descriptions |
Descriptions over 160 characters |
duplicate_fonts |
Theme fonts loaded again by custom CSS or scripts_head |
custom_css_overrides |
Custom CSS findings from lint_design_tokens: heavy !important use, fonts not in the theme, a first-section background image set in CSS, rules on platform block classes |
ai_crawler_zone_conflict |
The Cloudflare zone’s AI crawler settings against the site’s ai_crawler_policy |
structured_data |
Page JSON-LD missing required properties (FAQPage, Article, Product, SoftwareApplication, Event, Recipe, Organization and similar) or with invalid dates or URLs |
ai_crawler_zone_conflict reads the zone’s bot settings only through the
organization’s existing Cloudflare connection, and only when its token already
has Bot Management Read. Typeroll never asks for that permission for this
check and never changes zone settings. Without access, the item is a
suggestion that explains where to check in the Cloudflare dashboard. Blocking
Training in Cloudflare can also block Googlebot, Bingbot and Applebot, because
Cloudflare applies the strictest rule to crawlers that do several jobs.
How customer publishing works
Section titled “How customer publishing works”- Typeroll freezes the selected Site Version and its saved content.
- Generated source is committed to the Site’s GitHub repository and version branch.
- The Organization’s selected shared build engine (Cloudflare or GitHub Actions) builds with pinned dependencies and the publication’s media grants.
- Finished static files, including referenced public media, go to Cloudflare Pages in the Site’s Hosting Group account.
- Typeroll verifies the public deployment before exposing its link.
Published and unlisted pages can be deployed. Draft and review pages are
excluded. Unlisted pages use noindex; non-main versions and default-domain
demos also remain out of search indexes. Build times depend on the content,
provider queue, dependencies and media work.
One publication at a time per Organization
Section titled “One publication at a time per Organization”All Sites in an Organization share one build engine, and its runners take the
oldest task in the Organization. Publish one Site at a time: start the next
publication when the previous job has succeeded or failed and
read_organization_build_engine shows no active_jobs. Scripts read the same
status with an organization API key from GET /api/v1/publishing/builds; each
active job lists its job_id (a deploy id, or media-… for image preparation),
site_id, kind and status. A publication stays listed with status
publishing after its build, while its files upload and the public deployment
is verified, until its deploy reaches succeeded or failed. A domain switch
that is built and verified and only waits for DNS approval is listed under
awaiting_approval instead: it uses no build capacity and has released its
site’s publishing lock, so other Sites may publish while it waits. Concurrent
publications at best queue; up to Core 0.2.132 they could fail each other with
build_result_missing. That code means the build engine stopped without
reporting a result: a runner never ran the task, and the content did not cause
it. Publish again once the engine is idle. retry_deploy_verification does not
apply to it, nor to other build failures; it only retries public verification
of an already-served publication.
Legacy managed and self-hosted publishing can execute builds in the portal’s configured runtime. Reported server-cost estimates describe that runtime; they are not the customer’s Cloudflare or GitHub invoice.
Deploy URLs
Section titled “Deploy URLs”New customer-publishing sites use the assigned Hosting Group’s site address base
or their configured custom domain. They do not receive a permanent Typeroll
subdomain. The main version uses the live branch; other versions use
version-<version-id> branches and separate addresses.
A saved Published status is not a live-link guarantee. Wait for the job’s public availability verification. Use Publishing for setup and Website and media domains for domain changes.
Core 0.2.16 public probes do not require immediate deletion of retired versioned Extension or hashed Astro CSS/JavaScript bundles, which Cloudflare may retain. The exact candidate still checks their absence. Removed Pages/media and all current files remain verified. See verification and retired bundles.
retry_deploy_verification
Section titled “retry_deploy_verification”From Core 0.2.39 / MCP 0.45.32, an admin can retry public verification of a customer publication that timed out after its build and candidate checks finished and its files reached the public host. In the site overview, choose Retry verification beside the failed deployment. The server rejects incomplete builds, newer deployments for the same version, changed hosting and unrelated failure types. Correct the reported technical problem first.
The retry keeps the same job ID, saved source, Git commit and artifact. It checks
the real public marker and files, then updates CMS publication status only if
those checks pass. It does not build, upload, change DNS or publish later edits.
Poll get_deploy_status for the same job after requesting the retry.
{ "job_id": "deployment-id", "version": "main" }The equivalent authenticated API call is
POST /api/v1/sites/{siteId}/deploy?version=main with
{ "retry_verification_job_id": "deployment-id" }. Do not combine it with
dry_run. Requesting another retry while the same verification is running
returns the existing job; it does not start another verification chain.
Recovering stale hosting cache
Section titled “Recovering stale hosting cache”Core 0.2.117 / MCP 0.45.88 (pending release): retry also accepts
publication_cache_refresh_required, publication_cache_refresh_external and
publication_cache_refresh_failed. These describe a completed, already-served
build whose normal public URL still returns old bytes. Inspect static_probe
and cache_recovery in get_deploy_status; do not start a new build.
A domain preparation checks the files at the current address before it offers
the switch. When an old file is still cached there, Typeroll refreshes the cache
for that file’s path on that hostname only, as it does for a normal publication.
If the stale file persists, the job fails with
publication_cache_refresh_required and resumes through the same retry, with
or without an approved zone refresh. Traffic and DNS stay unchanged.
Without extra arguments, retry remains read-only. An administrator of the owning Organization can explicitly approve a zone-wide Cloudflare cache refresh:
{ "job_id": "deployment-id", "version": "main", "approve_cache_zone_id": "exact-zone-id-from-cache_recovery"}The API equivalent adds approve_cache_zone_id beside
retry_verification_job_id. Site-only credentials cannot approve this operation.
Personal OAuth access must select the owning Organization and have its owner or
admin role. Explain the zone name and scope to the owner before approval:
all cached content in that zone, including other sites and subdomains, is evicted.
Files and DNS are unchanged; initial requests can be slower while the cache refills.
Approval is bound to the recorded publication, zone and DNS connection. A changed
connection or superseded publication is rejected. A successful purge request does
not finish the job: Typeroll checks the normal public URLs against the same frozen
artifact. An unsuccessful broad refresh stops with
publication_cache_refresh_failed; it does not trigger a purge loop or a rebuild.