API Reference
Complete Rover docs for workspace key management, Rover Analytics Firestore data paths plus private settings callables, A2W run resources, and browser runtime contracts.
A2W run base: https://agent.rtrvr.ai/v2/a2w/runs · Runtime base: https://agent.rtrvr.ai/v2/rover/*
Auth Modes
Firebase ID tokenfor Workspace management APIs (/generateRoverSiteKey,/listRoverSiteKeys, and related config endpoints).sessionToken (rvrsess_*)for browser runtime calls to/v2/rover/*after session bootstrap.publicKey (pk_site_*)only for bootstrap exchange on/v2/rover/session/open. Do not sendsk_site_*to browser runtime.run access tokenfor the public A2W run URL returned by/v2/a2w/runs.Web Bot Auth (RFC 9421)HTTP Message Signatures for public A2W calls: sign withSignature+Signature-Inputand pointSignature-Agentat your key directory. Anonymous requests are accepted; a verified signature earns a higher trust tier that raises rate limits and unlocks sensitive capabilities.Rover delegation token (rds_*)— a key-bound, scoped, spend-capped human authorization carried asauth: { mode: "delegated_session", token }on A2W run create/continue. Minted by the verify loop (input.links.verify); never a raw site credential.Firebase auth + Firestore rulesfor owner-only Rover Analytics reads in Workspace, plus Firebase-authenticated callables for private settings such as notification subscriptions.
Agent-to-Web Protocol (A2W) API (`/v2/a2w/runs`)
Neutral AI / CLI protocol for Rover-enabled sites. POST is the structured API-agent path. GET /v2/a2w/runs is the compact URL-fetch chatbot path and can extract one canonical browser selector from the target URL. The source-visible marker <script type="application/agent+json"> stays compact and points agents to the live well-known files and OpenAPI.
/v2/a2w/runsCreate a strict v2 A2W run for any Rover-enabled site using a target URL and exactly one launch selector.
Auth: Anonymous public access token minted in response. Initial create call requires no site public key.
Required Request Fields
| Field | Type | Description |
|---|---|---|
url | string | Target page URL on a Rover-enabled site. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
prompt | string | Canonical natural-language instruction for the run. |
shortcutId | string | Exact saved shortcut/capability ID. Use for repeatable flows. |
playbookId | string | Exact experience playbook ID. Use when the owner has published a guided outcome path. |
engagementKind | 'demo' | 'onboarding' | 'support' | 'task' | Optional explicit kind. It must agree with a selected shortcut or playbook. |
capabilityId | string | Explicit page/site capability identifier when the caller already knows the target skill. |
args | Record<string, unknown> | Structured run arguments for the selected capability. |
identity | { userPresent?, sessionId?, agentKey?, memoryKey? } | Typed caller and session attribution. |
execution | { preference?: 'cloud' | 'browser' | 'auto'; mode?: 'cloud' | 'browser'; allowedModes?: ('cloud' | 'browser')[]; userPresent?: boolean } | Structured execution preference for POST callers. |
accept | { modes?, primary? } | Requested text, markdown, json, observation, or artifacts result modes. |
policy | { confirmation?, crossHost?, maxHops? } | Execution policy that the site may narrow. |
agent | { key?, displayName?, vendor?, model?, version?, homepage?, memoryKey?, clientId? } | Typed visiting-agent attribution. |
subject / auth / payment / commerce | typed objects | Sensitive or structured scoping accepted only on POST, never in browser or GET links. |
confirmationPolicy / artifacts | typed fields | Charge-confirmation policy and requested artifact names. |
{
"id": "a2w_run_123",
"protocol": "a2w",
"runId": "a2w_run_123",
"run": "https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_123?access=a2w_access_...",
"workflow": "https://agent.rtrvr.ai/v2/a2w/workflows/a2w_wf_456?access=a2w_access_...",
"status": "running",
"retryAfterMs": 2000,
"links": {
"poll": { "href": "https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_123?access=a2w_access_...", "method": "GET", "headers": { "Accept": "application/json", "Prefer": "wait=10" } },
"stream": { "href": "https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_123?access=a2w_access_...", "method": "GET", "headers": { "Accept": "text/event-stream" } },
"ndjson": { "href": "https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_123?access=a2w_access_...", "method": "GET", "headers": { "Accept": "application/x-ndjson" } }
},
"open": "https://www.rtrvr.ai/#rover_receipt=a2w_receipt_...",
"browserLink": "https://www.rtrvr.ai/?rover=get+me+the+latest+blog+post#rover_receipt=a2w_receipt_..."
}Notes
- Headers drive advanced behavior: `Accept`, `Prefer: wait=15`, `Prefer: execution=cloud|browser|auto`, and `Idempotency-Key`.
- Exactly one of `prompt`, `shortcutId`, or `playbookId` is required. Unknown properties and conflicting kinds fail with typed contract errors.
- If no explicit `agent` object is provided, Rover can still attribute the caller heuristically from `User-Agent`, `Signature-Agent`, `Signature`, `Signature-Input`, and `X-RTRVR-Client-Id`.
- Default execution mode is `cloud` for URL-fetch agents. `open` is the clean receipt-based browser handoff, while `browserLink` is an optional readable alias when the visible deep link stays within a conservative URL budget.
- Use `Prefer: execution=cloud, wait=10` for cloud-hosted execution with a short initial wait, then follow `links.stream`, `links.ndjson`, or `links.poll` until terminal or input_required.
/v2/a2w/runs?url=<target>&prompt=<task>Create a hosted-cloud A2W run for URL-fetch chatbots that cannot POST.
Auth: Anonymous public access token minted in response. Target site must have AI access and cloud browser execution enabled.
Required Request Fields
| Field | Type | Description |
|---|---|---|
url | string | Absolute HTTPS target page URL on a Rover-enabled site. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
prompt | string | Natural-language task. Use exactly one selector. |
shortcutId | string | Exact saved shortcut ID. Use exactly one selector. |
playbookId | string | Exact saved playbook ID. Use exactly one selector. |
engagementKind | 'demo' | 'onboarding' | 'support' | 'task' | Optional explicit kind; stored kinds remain authoritative. |
execution | 'cloud' | 'browser' | Defaults to cloud. |
wait | number | Initial long-poll wait in seconds. Defaults to 25 and caps server-side. |
format | 'markdown' | 'json' | Defaults to markdown unless JSON is requested. |
# Rover A2W run
Status: running
Run: https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_123?access=a2w_access_...
## Still running
Rover is running this task in a hosted cloud browser. Fetch the poll URL until terminal or input_required.
## Links
- Poll: https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_123?access=a2w_access_...&format=markdown&wait=10Notes
- This is the no-browser path for ChatGPT, Claude, Gemini, and similar URL-fetch agents.
- Long-running markdown responses include a self-contained poll URL with `format=markdown&wait=10`.
- GET executor responses send `X-Robots-Tag: noindex, nofollow, noarchive`.
/v2/a2w/runs/{id}Read the canonical public A2W run resource as JSON, markdown, SSE, or NDJSON.
Auth: Run access token via `?access=` or `Authorization: Bearer ...`.
Notes
- `Accept: application/json` returns latest state or final result.
- `format=markdown` returns chatbot-readable markdown.
- `Accept: text/event-stream` streams uniform run events.
- `Accept: application/x-ndjson` streams the same events in CLI-friendly NDJSON.
/v2/a2w/runs/{id}Continue a run that is waiting on user input.
Auth: Run access token.
Required Request Fields
| Field | Type | Description |
|---|---|---|
input | string | Ordinary continuation answer. Required unless `answers` is sent. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
answers | Record<string, string> | Per-question answers keyed by `input.questions[].key` — use this when the park asked multiple questions. A bare `input` string binds the same text to every key; unknown keys are ignored. |
Notes
- Only for ordinary `input_required` questions. Reasons carrying `input.links.confirm` or `input.links.verify` (payment_confirmation_required, auth_required, action_confirmation_required, ...) complete out-of-band — relay the link to the human and poll; do not POST input to those runs.
- Sign-in walls (`input.reason=sign_in_link_required`) resume via POST /v2/a2w/runs/{id}/auth-input instead.
/v2/a2w/runs/{id}/auth-inputProvide the sign-in magic link or one-time code a human received, so a run parked with input.reason=sign_in_link_required can resume.
Auth: Run access token.
Required Request Fields
| Field | Type | Description |
|---|---|---|
value | string | The sign-in link or one-time code. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
kind | 'magic_link' | 'otp' | 'unknown' | Required type of the one-shot value. |
Notes
- The value is a secret: stored encrypted, consumed one-shot to resume the run, and never returned in any payload, event, or model context.
- `run.authInput` describes what is expected (`status`, `kind`, `prompt`, `emailMasked`) and never carries the provided value.
- Returns the updated run resource; resume is driven asynchronously — keep polling `links.self`.
/v2/a2w/runs/{id}Cancel an in-flight A2W run.
Auth: Run access token.
/v2/a2w/runs/{id}/artifactsMint short-lived signed download URLs for the files a run generated (screenshots, PDFs, sheets).
Auth: Run access token.
Notes
- The run result lists generated files as opaque storage refs; this endpoint turns them into fetchable URLs on read.
- Signed URLs expire after ~15 minutes — re-GET to refresh. Runs that produced files advertise this endpoint as `links.artifacts`.
- Response shape: `{ runId, expiresAt, artifacts: [{ name, contentType, sizeBytes, url, expiresAt }] }`.
/v2/a2w/capabilities?url=<site>List a Rover-enabled site's published capabilities as MCP-shaped tools.
Auth: Anonymous. RFC 9421 Web Bot Auth signing raises the trust tier.
Required Request Fields
| Field | Type | Description |
|---|---|---|
url | string | Target site URL. Required unless `host` or `siteId` is passed. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
host | string | Site host, as an alternative to `url`. |
siteId | string | Explicit Rover site identifier. |
Notes
- Returns `{ protocol: 'mcp', serverInfo, executor: { contract: 'a2w', runEndpoint }, mcp: { transport: 'streamable-http', url }, tools }`.
- Every tool executes Rover-mediated through the canonical A2W run contract; MCP-native agents can instead connect to the returned live MCP server URL.
/v2/a2w/runs/{id}/handoffsCreate a delegated child run on another Rover-enabled site and keep the same workflow lineage.
Auth: Parent run access token.
Required Request Fields
| Field | Type | Description |
|---|---|---|
url | string | Target Rover-enabled site URL. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
prompt | string | Delegation request. Use exactly one selector. |
shortcutId | string | Exact shortcut to run on the receiving site. |
playbookId | string | Exact playbook to run on the receiving site. |
engagementKind | 'demo' | 'onboarding' | 'support' | 'task' | Optional explicit kind; it must agree with stored configuration. |
capabilityId | string | Explicit child-run capability identifier. |
args | Record<string, unknown> | Structured arguments for the delegated capability. |
identity | { userPresent?, sessionId?, agentKey?, memoryKey? } | Typed child-run identity hints. |
execution | { preference?, mode?, allowedModes?, userPresent? } | Cloud/browser execution policy for the child run. |
accept | { modes?: ('text' | 'markdown' | 'json' | 'observation' | 'artifacts')[] } | Requested child-run result modes. |
policy | { confirmation?: 'auto' | 'required' | 'site_policy'; crossHost?: 'allow' | 'same_host' | 'site_policy' } | Execution-policy hints for the child run. |
agent | { key?, displayName?, vendor?, model?, version?, homepage?, memoryKey?, clientId? } | Optional child-run agent identity override. If omitted, parent attribution is inherited. |
contextSummary | string | Structured summary to carry into the child run. |
expectedOutput | string | Describe what the child should return to the parent workflow. |
lastObservation | Record<string, unknown> | Latest structured parent observation when needed for delegation. |
Notes
- Delegated child runs are still ordinary A2W run resources; they simply inherit the parent's workflow lineage.
- Receiving sites must enable `siteConfig.aiAccess.allowDelegatedHandoffs` in Workspace.
/v2/a2w/workflows/{id}Read the aggregated cross-site workflow resource as JSON, SSE, or NDJSON.
Auth: Workflow access token via `?access=` or `Authorization: Bearer ...`.
Notes
- `Accept: application/json` returns the latest workflow snapshot and final result when available.
- `Accept: text/event-stream` or `Accept: application/x-ndjson` streams workflow-level lineage across parent and child runs.
Workspace Management APIs
Used by Rover Workspace for key lifecycle and site config management. These remain Firebase-authenticated control-plane endpoints.
Cloud site config persists shortcuts, business type, sparse Rover V3 experience overrides, greeting, voice dictation, AI access policy, agent discovery policy, per-site page-capture overrides, and site-owned mascot appearance controls. Runtime-owned defaults still control the seed CTA, bottom-center anchor, transparent live-action mode, and default live-card count unless you explicitly override those fields. Explicit boot-only overrides such as deepLink.* still stay outside these workspace endpoints.
/generateRoverSiteKeyCreate a new Rover site key and persisted policy/profile.
Auth: Firebase ID token (Bearer)
Required Request Fields
| Field | Type | Description |
|---|---|---|
siteId | siteName | string | Existing siteId or a siteName for server-generated siteId. |
label | string | Human-readable key label. |
allowedDomains | string[] | Allowed host/domain patterns (`example.com`, `*.example.com`, `=app.example.com`, or URL-shaped entries normalized to host). In `registrable_domain`, plain `example.com` covers the apex host and subdomains. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
ttlDays | number | Expiration days, use 0 for no expiry. |
environment | 'production' | 'development' | 'test' | Deployment environment label. |
capabilities | { roverEmbed?, externalWebContextScrape?, cloudAgent?, cloudScrape? } | Capability profile for this key. |
roverPolicy | RoverSitePolicy | Policy persisted and returned in list/replace APIs, including `siteMode`, `domainScopeMode`, `cloudSandboxEnabled`, mascot settings, and shortcut limits. |
/listRoverSiteKeysList all Rover site keys for the authenticated workspace user.
Auth: Firebase ID token (Bearer)
/updateRoverSiteKeyPolicyPatch a key's allowed domains, active status, capabilities, and Rover policy.
Auth: Firebase ID token (Bearer)
Required Request Fields
| Field | Type | Description |
|---|---|---|
keyId | string | Target key identifier. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Optional site assertion/update. |
allowedDomains | string[] | Replacement domain pattern set (`example.com`, `*.example.com`, `=app.example.com`, or URL-shaped entries). In `registrable_domain`, plain `example.com` covers the apex host and subdomains. |
active | boolean | Enable/disable key. |
capabilities | ApiKeyCapabilities | Capability patch. |
roverPolicy | Partial<RoverSitePolicy> | Policy patch, including `siteMode`, `domainScopeMode`, `cloudSandboxEnabled`, mascot settings, and shortcut limits. |
/rotateRoverSiteKeyRotate a key (invalidate old key and issue a new pk_site_* value).
Auth: Firebase ID token (Bearer)
Required Request Fields
| Field | Type | Description |
|---|---|---|
keyId | string | Key being rotated. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Optional site assertion/update. |
label | string | Optional new label. |
capabilities | ApiKeyCapabilities | Capability patch applied to rotated key. |
roverPolicy | Partial<RoverSitePolicy> | Policy patch applied to the replacement key, including `siteMode`, `domainScopeMode`, `cloudSandboxEnabled`, mascot settings, and shortcut limits. |
/deleteRoverSiteDelete a Rover site, all owned site keys, and Rover-owned config while retaining historical Rover Analytics.
Auth: Firebase ID token (Bearer)
Required Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Rover site identifier to delete. |
Notes
- Deletes all owned Rover site keys for the site, plus Rover-owned site config and Rover Analytics owner settings/questions.
- Historical Rover Analytics, visits, reviews, interviews, notes, posts, and aggregates are retained.
- Webflow-managed sites are detached from the live managed Webflow install before Rover-owned resources are removed.
/getRoverSiteConfigRead cloud shortcuts, business type, sparse experience overrides, greeting, voice, AI access, discovery, and page-capture config for a key/site.
Auth: Firebase ID token (Bearer)
Required Request Fields
| Field | Type | Description |
|---|---|---|
keyId | string | Site key ID. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Optional site assertion. |
/upsertRoverSiteConfigWrite cloud shortcuts, business type, sparse experience overrides, greeting, voice, AI access, discovery, and page-capture config.
Auth: Firebase ID token (Bearer)
Required Request Fields
| Field | Type | Description |
|---|---|---|
keyId | string | Site key ID. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Optional site assertion. |
siteConfig.shortcuts | RoverSiteShortcut[] | Persisted shortcuts/journeys. |
siteConfig.businessType | RoverBusinessType | Tunes runtime placeholder hints and generated quick actions when the site has few explicit shortcuts. |
siteConfig.experience | RoverSiteExperience | null | Sparse Rover V3 surface overrides only. Runtime defaults still own the seed, centered stage, and focus stream when a field is omitted. Use null to clear overrides. |
siteConfig.greeting | { text?, delay?, duration?, disabled? } | null | Greeting config. |
siteConfig.voice | { enabled?: boolean; language?: string; autoStopMs?: number } | null | Browser dictation config. autoStopMs is the post-speech silence window in milliseconds. Use null to clear persisted voice settings. |
siteConfig.aiAccess | RoverSiteAiAccess | null | Public launch/runtime guardrails for A2W run entry, browser deep links, cloud browser use, and delegated handoffs. |
siteConfig.analytics | { enabled?: boolean; consent?: { provider: 'wix'; category: 'analytics' } } | null | Per-site Activity analytics switch and optional host consent gate. Wix installs use this to keep Activity default-on for owners while requiring Wix analytics consent from visitors. |
siteConfig.agentDiscovery | RoverSiteAgentDiscovery | null | Persisted public discovery policy, well-known artifact paths, host-surface binding, and seed/presence-led display settings. Use null to clear. |
siteConfig.pageConfig | RoverPageCaptureConfig | null | Sparse per-site page-capture overrides. New generated installs default disableAutoScroll to true; use null to clear overrides. |
/updateApiKeyCapabilitiesPatch capability flags for user or site keys.
Auth: Firebase ID token (Bearer)
Required Request Fields
| Field | Type | Description |
|---|---|---|
keyId | string | Target key identifier. |
capabilities | ApiKeyCapabilities | Boolean capability patch fields. |
Rover Analytics Workspace Data Paths
Rover Analytics pages now read aggregate-first Firestore summaries directly under owner-auth rules, including first-party identity/account filters backed by hashed join keys. Backend callables remain for private settings and Storage-backed trajectory hydration. These are distinct from public site-tag ingest routes and are not public `siteId` browser APIs.
Firestore: roverbook_* collectionsOwner-facing Rover Analytics now read Firestore directly under ownership rules instead of calling a backend read facade.
Auth: Firebase auth + Firestore rules (`ownerUid` scoped).
Notes
- Workspace reads `roverbook_sites`, `roverbook_interactions`, daily aggregate docs, identity/account profile summaries, `roverbook_visits`, `roverbook_scores`, `roverbook_reviews`, `roverbook_interviews`, `roverbook_questions`, `roverbook_notes`, and `roverbook_posts` directly.
- Raw event docs and anonymous-to-known identity links remain backend-only. User/account IDs are stored as hashed join keys unless a site explicitly opts into display PII.
- Signed public analytics GET routes still exist for runtime/agent surfaces used by the internal `@rover/roverbook` package.
getRoverBookInteractionDetailHydrate one Rover Analytics interaction detail, including Storage-backed trajectory data, after owner access is verified.
Auth: Firebase ID token (owner only).
Required Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Owned Rover site identifier. |
interactionId | string | Rover Analytics interaction identifier. |
Notes
- Workspace uses this for on-demand detail drawers so browser clients never read `roverbook-interactions/...` Storage blobs directly.
getRoverBookNotificationSettingsRead the private Rover Analytics setup payload for a site, including interview questions and masked webhook subscriptions.
Auth: Firebase ID token (owner only).
Required Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Owned Rover site identifier. |
upsertRoverBookNotificationSettingsWrite Rover Analytics interview questions and webhook subscriptions for a site.
Auth: Firebase ID token (owner only).
Required Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Owned Rover site identifier. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
enabled | boolean | Enable or disable Rover Analytics outbound notifications for the site. |
webhooks | RoverAnalyticsWebhookSubscription[] | Private per-site webhook subscription list. |
interviewQuestions | string[] | Per-site Rover Analytics interview prompts. |
Notes
- Webhook secrets are masked on read and preserved unless explicitly replaced.
- These settings are stored privately by owner + site and are not exposed through public embed config.
upsertRoverBookQuestionsWrite just the Rover Analytics interview questions for a site.
Auth: Firebase ID token (owner only).
Required Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Owned Rover site identifier. |
interviewQuestions | string[] | Per-site Rover Analytics interview prompts. |
Rover Runtime APIs (`/v2/rover/*`)
Server-authoritative runtime contract for embedded Rover. All run-state changes are keyed bysessionId + runId + epoch + seq.
/v2/rover/session/openBootstrap or refresh a browser runtime session and return the initial projection.
Auth: Body token. Preferred: bootstrapToken/publicKey (pk_site_*). Optional: sessionToken refresh path.
Required Request Fields
| Field | Type | Description |
|---|---|---|
siteId | string | Workspace site identifier. |
host | url | string | Current host/url for domain and policy checks. |
bootstrapToken | publicKey | string | Public Rover key (pk_site_*). Required when no valid sessionToken is supplied. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | string | Optional local correlation hint. Public-key bootstrap always returns a new backend-minted random session ID. |
sessionToken | string | Current rvrsess_* token. If invalid/expired and bootstrap token exists, server falls back to bootstrap flow. |
visitor.context | RoverExperienceContextV1 | Safe data-only profile, account, intent, success, support, recent-activity, and primitive-fact hints. Sanitized and capped at 2 KB; recent activity is historical background and limited to three requests. |
visitor.contextToken | string | Opaque site-server-minted token, max 2,048 chars. Exchanged once when context_token_v1 is enabled; never persisted raw. |
{
"success": true,
"data": {
"sessionId": "8ef5202c-6e2b-4f1b-9fc7-925564f65e77",
"sessionToken": "rvrsess_...",
"sessionTokenExpiresAt": 1771484403000,
"streamToken": "rvrstream_...",
"epoch": 5,
"capabilities": { "roverEmbed": true },
"policy": {
"domainScopeMode": "registrable_domain",
"cloudSandboxEnabled": true,
"externalAllowDomains": [],
"externalDenyDomains": []
},
"projection": { "sessionId": "8ef5202c-6e2b-4f1b-9fc7-925564f65e77", "epoch": 5, "events": [], "tabs": [] },
"siteConfig": {
"shortcuts": [],
"businessType": "saas",
"experience": {
"presence": { "ctaText": "Do it with Rover" },
"inputs": { "voice": false }
},
"greeting": { "text": "Welcome" },
"voice": { "enabled": true, "language": "en-US", "autoStopMs": 2600 },
"aiAccess": { "enabled": true },
"agentDiscovery": {
"enabled": true,
"preferExecution": "cloud",
"roverSiteUrl": "/.well-known/rover-site.json",
"agentCardUrl": "/.well-known/agent-card.json",
"discoverySurface": {
"mode": "beacon",
"branding": "site",
"hostSurface": "auto",
"actionReveal": "click",
"beaconLabel": "Use AI"
}
},
"pageConfig": { "disableAutoScroll": true, "adaptiveSettleMaxWaitMs": 480 }
},
"sseUrl": "https://agent.rtrvr.ai/v2/rover/stream?..."
}
}Typed Conflict/Auth Errors
{
"success": false,
"error": "SESSION_TOKEN_EXPIRED",
"data": {
"code": "SESSION_TOKEN_EXPIRED",
"message": "Token expired",
"retryable": true,
"next_action": "Pass bootstrapToken/publicKey (pk_site_*) to /v2/rover/session/open to re-bootstrap the session."
}
}{
"success": false,
"error": "BOOTSTRAP_REQUIRED",
"data": {
"code": "BOOTSTRAP_REQUIRED",
"message": "bootstrapToken/publicKey (pk_site_*) is required.",
"retryable": false,
"next_action": "Provide a valid pk_site_* key in bootstrapToken/publicKey."
}
}Notes
- Server mints short-lived sessionToken (~10 min).
- Browser runtime should not send long-lived bearer keys.
- Standard owner-facing Workspace installs rely on Rover's built-in tab behavior instead of owner-selected tab overrides.
/v2/rover/session/openRefresh an existing rvrsess_* token and SSE URL.
Auth: sessionToken
Required Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | string | Session to refresh (defaults to token sid). |
Notes
- Use when token is near expiry or after SSE auth failures.
/v2/rover/session/contextRefresh sanitized experience context after login, account, plan, or journey changes.
Auth: sessionToken
Required Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | string | Active Rover session. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
visitor.context | RoverExperienceContextV1 | Safe immediate hints only. Send visitor: null to clear local and server personalization on logout. |
visitor.contextToken | string | New opaque site-server-minted token. |
Notes
- The resolver fails open. Raw tokens and raw resolver payloads never enter prompts, logs, checkpoints, receipts, or URLs.
/v2/rover/commandSubmit user input and create/continue an authoritative run.
Auth: sessionToken
Required Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | string | Target session. |
message | string | User message. |
expectedEpoch | number | Required in strict mode for stale-epoch protection. |
clientEventId | string | Idempotency key for retries and dedup. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
continueRun | boolean | Continue active run. Reserved for ask_user answer continuation in the same task boundary. |
forceNewRun | boolean | Cancel active run and create a fresh run. Normal user sends should set this true. |
expectedSeq | number | Required in strict mode when active run exists. |
requestedMode | 'act' | 'planner' | 'auto' | Routing preference. `act`/`planner` force backend mode; `auto` uses heuristic routing. |
taskBoundaryId | string | Optional client task boundary identifier. |
{
"success": true,
"data": {
"runId": "run-uuid",
"acceptedMode": "act",
"state": "running",
"continuePrompt": false,
"requestedMode": "act",
"epoch": 5,
"seq": 1
}
}Typed Conflict/Auth Errors
{
"success": false,
"error": "stale_epoch",
"data": {
"sessionId": "8ef5202c-6e2b-4f1b-9fc7-925564f65e77",
"runId": "run-uuid",
"expectedEpoch": 2,
"currentEpoch": 5,
"decisionReason": "stale_epoch_retryable",
"conflict": { "type": "stale_epoch", "currentEpoch": 5, "retryable": true }
}
}{
"success": false,
"error": "active_run_exists",
"data": {
"continuePrompt": true,
"runId": "run-uuid",
"state": "running",
"acceptedMode": "act",
"decisionReason": "active_run_exists",
"conflict": { "type": "active_run_exists", "retryable": false }
}
}Notes
- One active run per session is enforced server-side.
- No local silent fallback should run when this call is not accepted.
/v2/rover/commandControl run lifecycle (`cancel`, `end_task`, `new_task`, `continue`).
Auth: sessionToken
Required Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | string | Target session. |
action | 'cancel' | 'end_task' | 'new_task' | 'continue' | Requested run control action. |
expectedEpoch | number | Required in strict mode. |
clientEventId | string | Idempotency key. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
runId | string | Required for `cancel` and `end_task` when active run is not implied. |
expectedSeq | number | Strict stale-seq guard for run-scoped actions. |
reason | string | Audit reason for control action. |
{
"success": true,
"data": {
"action": "cancel",
"runId": "run-uuid",
"currentSeq": 18,
"projection": { "sessionId": "8ef5202c-6e2b-4f1b-9fc7-925564f65e77", "epoch": 6, "activeRunId": "", "events": [], "tabs": [] }
}
}Notes
- Use clientEventId for idempotent retries.
- Strict mode requires expectedEpoch and enforces stale rejection before state transitions.
/v2/rover/commandSubmit navigation/tab intent and receive authoritative policy decision.
Auth: sessionToken
Required Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | string | Target session. |
targetUrl | url | string | Navigation destination. |
expectedEpoch | number | Required in strict mode. |
clientEventId | string | Idempotency key used for silent retry recovery. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
runId | string | Intended active run (defaults to session active run). |
expectedSeq | number | Strict stale-seq guard for run-scoped events. |
currentUrl | string | Current browser URL. |
currentHost/targetHost/isCrossHost/navigationClass | hints | Client hints. Server computes authoritative class regardless. |
logicalTabId | string | Logical tab identifier for run tab graph. |
message | string | Prompt context used for adversarial scoring. |
adversarialScore | number | Optional explicit score (merged with server score). |
{
"success": true,
"data": {
"decision": "allow_same_tab",
"decisionReason": "allow_same_tab",
"decisionHint": "allow_same_tab",
"notice": "In-scope navigation allowed.",
"staleRun": false,
"sessionId": "8ef5202c-6e2b-4f1b-9fc7-925564f65e77",
"sessionEpoch": 5,
"runId": "run-uuid",
"currentSeq": 3,
"clientEventId": "evt-uuid",
"currentHost": "www.rtrvr.ai",
"targetHost": "rtrvr.ai",
"isCrossHost": true,
"crossDomain": false,
"navigationClass": "cross_host_in_scope",
"adversarial": { "score": 0, "reasons": [] }
}
}Typed Conflict/Auth Errors
{
"success": false,
"error": "stale_seq",
"data": {
"sessionId": "8ef5202c-6e2b-4f1b-9fc7-925564f65e77",
"runId": "run-uuid",
"expectedSeq": 2,
"currentSeq": 3,
"currentEpoch": 5,
"decisionReason": "stale_seq_retryable",
"clientEventId": "evt-uuid",
"conflict": { "type": "stale_seq", "currentSeq": 3, "currentEpoch": 5, "retryable": true }
}
}{
"success": true,
"data": {
"decision": "stale_run",
"decisionReason": "stale_run",
"staleRun": true,
"staleRunReason": "run_terminal",
"currentRunId": "new-active-run-id",
"currentActiveRunId": "new-active-run-id",
"sessionEpoch": 6,
"decisionHint": "sync_projection_and_ignore"
}
}Notes
- Server keeps strict stale checks and returns typed 409 envelopes.
- SDK should do one silent retry on stale conflicts with same clientEventId.
- Stale/missing run is non-fatal via `decision=stale_run` (200).
/v2/rover/streamSSE stream for projection updates and keepalive pings.
Auth: Short-lived, stream-only rvrstream_* ticket in the query. The session token is never placed in the URL.
Required Request Fields
| Field | Type | Description |
|---|---|---|
streamTicket | query string | Opaque audience-limited stream ticket. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
seqAfter | number | Start events after this sequence. |
Notes
- SSE events: `ready`, `projection`, `ping`, `error`.
- Use POST /v2/rover/state as polling fallback.
/v2/rover/stateFetch latest projection (session/run/tabs/events/snapshot metadata).
Auth: sessionToken
Required Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | body | Backend-minted session identifier. |
sessionToken | body | Signed session credential. Never place it in a URL. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
seqAfter | number | Return events after this sequence only. |
/v2/rover/snapshotUpsert byte-compacted checkpoint/snapshot for resume. Firestore stores metadata and small inline checkpoints; oversized payloads are offloaded to backend storage.
Auth: sessionToken
Required Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | string | Target session. |
checkpoint | payload | object | Compacted snapshot payload. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
visitorId | string | Optional non-authoritative analytics correlation only; signed session claims own the checkpoint. |
updatedAt | number | Client timestamp in ms. |
version | number | Snapshot schema version. |
seq | number | Last stable seq captured in snapshot. |
compactedPrevSteps | unknown[] | Compacted execution history. |
chatSummary | string | Conversation summary text. |
ttlHours | number | TTL for snapshot document. |
/v2/rover/context/externalFetch/act on external context through policy-scoped cloud integrations.
Auth: sessionToken
Required Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | string | Target session. |
runId | string | Active run ID. |
url | string | External target URL. |
intent | 'open_only' | 'read_context' | 'act' | External action intent. |
expectedEpoch | number | Strict stale-epoch guard. |
expectedSeq | number | Strict stale-seq guard. |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
logicalTabId | string | Logical external tab id. |
message | userInput | string | Used for adversarial gating and context. |
timeoutMs | number | External fetch timeout. |
Notes
- Policy/capability checks are enforced server-side for each call.
- High adversarial score can block external context/action even when policy allows it.
/v2/rover/telemetry/ingestIngest runtime telemetry batches (diagnostics/observability).
Auth: sessionToken
Required Request Fields
| Field | Type | Description |
|---|---|---|
sessionId | string | Target session. |
events | unknown[] | Telemetry event batch (server truncates to safe limits). |
Optional Request Fields
| Field | Type | Description |
|---|---|---|
runId | string | Active run association. |
flushReason | string | Flush reason (`interval`, `manual`, etc.). |
pageUrl | string | Current page url. |
sampleRate | number | Client telemetry sample rate. |
sdkVersion | string | SDK version marker. |
Notes
- This endpoint is automatic; users do not need manual setup for normal onboarding.
- Telemetry ingestion does not replace run/state APIs.
Canonical Runtime Envelopes
type RoverSuccessResponse<T> = {
success: true
data: T
}type RoverErrorResponse = {
success: false
error: string
data?: {
code?: string
message?: string
retryable?: boolean
next_action?: string
decisionReason?: string
conflict?: {
type: 'stale_seq' | 'stale_epoch' | 'active_run_exists'
currentSeq?: number
currentEpoch?: number
retryable: boolean
}
}
}type TabEventDecisionResponse = RoverSuccessResponse<{
decision: 'allow_same_tab' | 'open_new_tab' | 'block' | 'stale_run'
decisionReason: 'allow_same_tab' | 'open_new_tab' | 'policy_blocked' | 'stale_run'
decisionHint: string
notice?: string
staleRun: boolean
staleRunReason?: string
currentRunId?: string
currentActiveRunId?: string
sessionId: string
sessionEpoch: number
runId?: string
currentSeq?: number
clientEventId?: string
currentHost?: string
targetHost?: string
isCrossHost?: boolean
crossDomain?: boolean
navigationClass?: 'same_host_in_scope' | 'cross_host_in_scope' | 'cross_registrable_external'
adversarial?: { score: number; reasons: string[] }
}>type RunInputResponse = RoverSuccessResponse<{
runId?: string
acceptedMode?: 'act' | 'planner'
state?: 'queued' | 'running' | 'awaiting_user' | 'cancel_requested' | 'cancelled' | 'completed' | 'failed'
continuePrompt?: boolean
requestedMode?: 'act' | 'planner' | 'auto'
epoch?: number
seq?: number
routing?: { score: number; reason: string }
}>type RunControlResponse = RoverSuccessResponse<{
action: 'cancel' | 'end_task' | 'new_task' | 'continue'
runId?: string
currentSeq?: number
projection: SessionProjectionResponse
}>type RunTransitionPayload = {
runId: string
status: 'queued' | 'running' | 'awaiting_user' | 'cancel_requested' | 'cancelled' | 'completed' | 'failed'
continuationReason?: 'loop_continue' | 'same_tab_navigation_handoff' | 'awaiting_user'
}type SessionProjectionResponse = {
sessionId: string
epoch: number
activeRunId?: string
runStatus?: 'queued' | 'running' | 'awaiting_user' | 'cancel_requested' | 'cancelled' | 'completed' | 'failed'
runMode?: 'act' | 'planner'
events: Array<{ seq: number; type: string; ts: { _seconds: number; _nanoseconds: number }; data?: Record<string, unknown> }>
tabs: Array<{ logicalTabId: string; parentLogicalTabId?: string; scope: 'in_scope' | 'external'; status: 'open' | 'blocked' | 'scraped' | 'acted' | 'closed'; url?: string; reason?: string; updatedAt: number }>
snapshot?: Record<string, unknown> // present only for bootstrap/resync; large snapshots may be hydrated from storage
snapshotUpdatedAt?: number
}// GET /v2/rover/stream emits:
// event: ready data: { sessionId, ts }
// event: projection data: SessionProjectionResponse
// event: ping data: { ts }
// event: error data: { message }
type A2WInputReason =
| 'auth_required'
| 'sign_in_link_required'
| 'account_link_required'
| 'payment_method_required'
| 'payment_confirmation_required'
| 'action_confirmation_required'
| 'human_verification_required'
| 'browser_takeover_required'
| 'merchant_policy_blocked'
| 'risk_review_required'
| 'terms_acknowledgement_required'
| 'offer_claim_required'
type A2WRun = {
id: string
protocol?: 'a2w'
runId: string
run: string
status: 'pending' | 'waiting_browser' | 'running' | 'input_required' | 'completed' | 'failed' | 'cancelled' | 'expired'
open?: string
links?: {
// self, poll, stream, ndjson, workflow, continue, cancel, open, browserLink ...
// artifacts appears when the run produced files — GET it for signed download URLs.
artifacts?: { href: string; method?: 'GET' }
[rel: string]: unknown
}
input?: {
reason?: A2WInputReason
message?: string
questions?: unknown[]
// Confirm/verify links live HERE, never on top-level links:
// relay them to the human and poll — do not POST input for those reasons.
links?: { confirm?: string; verify?: string; open?: string }
expiresAt?: string
}
authInput?: {
// Sign-in resume status (sign_in_link_required). Never carries the provided value.
status?: 'awaiting' | 'provided' | 'consumed'
kind?: 'magic_link' | 'otp' | 'unknown'
prompt?: string
emailMasked?: string
}
result?: {
text?: string
blocks?: unknown[]
summary?: string
observation?: { url?: string; title?: string; host?: string; summary?: string }
transcript?: { messages?: Array<{ role?: string; text?: string; ts?: number }> }
artifacts?: Record<string, unknown>[]
}
}// GET /v2/a2w/runs/{id} with SSE or NDJSON emits:
// ready
// status
// step
// tool
// message
// observation
// input
// done
// error
//
// Uniform envelope:
// { id, type, ts, data, chunked?, chunkIndex?, chunkCount?, artifactRef? }Conflict and Auth Semantics
409 stale_seqwhenexpectedSeqis stale/missing (strict mode) for mutable run-scoped calls.409 stale_epochwhenexpectedEpochis stale/missing (strict mode) for mutable calls.409 active_run_existson concurrent run creation races (typed conflict, no generic unknown error).200 decision='stale_run'for non-fatal stale/missing run inPOST /commandwithtype='TAB_EVENT'.- If command-based tab preflight is temporarily unavailable, SDK falls back to local smart-tab checks instead of hard-blocking navigation.
401 SESSION_TOKEN_EXPIRED,401 SESSION_TOKEN_INVALID, and401 BOOTSTRAP_REQUIREDfor typed auth flows.
Run Lifecycle and Continuity Semantics
- Hard invariant: one active run per session, enforced in backend store/ledger.
requestedModeinPOST /commandpayloads withtype='RUN_INPUT':actandplannerforce backend mode;autouses heuristic routing.- SDK default: normal user sends are fresh task boundaries with
forceNewRun=true(freshprevSteps+ tab scope). continueRun=trueis used only forask_useranswer submission on the active boundary.- Heuristic follow-up chat carryover is cue-only (
followupChatLogin worker payloads), and never carries prior task state. - Worker-to-SDK continuation semantics:
loop_continue,same_tab_navigation_handoff,awaiting_user. - Navigation outcome semantics:
same_tab_scheduled,new_tab_opened,blocked. - Stale seq/epoch races are expected under concurrent navigation/events; SDK should perform one silent retry for command-based tab stale conflicts.