[ documentation ]

API Reference

Complete Dayside reference for workspace key management, analytics Firestore data paths plus private settings callables, A2W run resources, and browser runtime contracts.

A2W run base: https://agent.rtrvr.ai/v1/a2w/runs · Runtime base: https://agent.rtrvr.ai/v2/rover/* (wire endpoints kept for protocol compatibility).

Auth Modes

  • Firebase ID token for 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 send sk_site_* to browser runtime.
  • run access token for the public A2W run URL returned by /v1/a2w/runs.
  • Firebase auth + Firestore rules for owner-only analytics reads in Workspace, plus Firebase-authenticated callables for private settings such as notification subscriptions.

Agent-to-Web Protocol (A2W) API (/v1/a2w/runs)

Neutral AI / CLI protocol for Dayside-enabled sites. POST remains canonical for API agents. GET /v1/a2w/runs is the URL-fetch chatbot path for ordinary target URLs and URLs that already contain rover or rover_shortcut. The source-visible marker <script type="application/agent+json"> is optional but recommended for raw HTML discovery, and generated cards also publish rover_exec guidance.

POST/v1/a2w/runs

Create a neutral A2W run for any Dayside-enabled site using a target URL plus a canonical prompt or shortcut envelope.

Auth: Anonymous public access token minted in response. Initial create call requires no site public key.

Required Request Fields

FieldTypeDescription
urlstringTarget page URL on a Dayside-enabled site.

Optional Request Fields

FieldTypeDescription
promptstringCanonical natural-language instruction for the run.
goalstringCompatibility alias for prompt.
shortcutIdstringExact saved shortcut/capability ID. Use for repeatable flows.
capabilityIdstringExplicit page/site capability identifier when the caller already knows the target skill.
argsRecord<string, unknown>Structured run arguments for the selected capability.
target{ pageId?, route?, capabilityId?, entityId?, formId? }Optional page/entity/form targeting hints.
identity{ userPresent?, signature?, signatureInput?, verificationMethod? }Structured caller/user-presence and verification hints.
execution{ preference?: 'cloud' | 'browser' | 'auto' | 'device'; userPresent?: boolean }Execution and user-presence hints. `device` is accepted as a browser/on-device alias. Prefer the `Prefer: execution=...` header for public A2W calls.
accept{ modes?: ('text' | 'markdown' | 'json' | 'observation' | 'artifacts')[] }Requested result modes.
policy{ confirmation?: 'auto' | 'required' | 'site_policy'; crossHost?: 'allow' | 'same_host' | 'site_policy' }Execution-policy hints that the site may honor or narrow.
agent{ key?, name?, vendor?, model?, version?, homepage? }Optional self-reported visiting-agent metadata used by attribution and analytics.
Success Example
{
  "id": "a2w_run_123",
  "protocol": "a2w",
  "runId": "a2w_run_123",
  "run": "https://agent.rtrvr.ai/v1/a2w/runs/a2w_run_123?access=a2w_access_...",
  "workflow": "https://agent.rtrvr.ai/v1/a2w/workflows/a2w_wf_456?access=a2w_access_...",
  "status": "running",
  "retryAfterMs": 2000,
  "links": {
    "poll": { "href": "https://agent.rtrvr.ai/v1/a2w/runs/a2w_run_123?access=a2w_access_...", "method": "GET", "headers": { "Accept": "application/json", "Prefer": "wait=10" } },
    "stream": { "href": "https://agent.rtrvr.ai/v1/a2w/runs/a2w_run_123?access=a2w_access_...", "method": "GET", "headers": { "Accept": "text/event-stream" } },
    "ndjson": { "href": "https://agent.rtrvr.ai/v1/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`. `execution=device` is accepted as a browser/on-device alias.
  • `prompt`, `shortcutId`, `capabilityId`, `args`, `target`, `identity`, `execution`, `accept`, and `policy` are the canonical A2W run shape. `goal` remains accepted as an alias.
  • If no explicit `agent` object is provided, Dayside 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.
GET/v1/a2w/runs?url=<target>&prompt=<task>&execution=cloud&wait=25&format=markdown

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

FieldTypeDescription
urlstringAbsolute HTTPS target page URL on a Dayside-enabled site.

Optional Request Fields

FieldTypeDescription
promptstringNatural-language task. Required unless `shortcutId` is present.
shortcutIdstringExact saved shortcut ID. Required unless `prompt` is present.
execution'cloud' | 'browser' | 'device' | 'auto'Defaults to `cloud` for GET create; `device` maps to browser/on-device execution.
waitnumberInitial long-poll wait in seconds. Defaults to 25 and caps server-side.
format'markdown' | 'json'Defaults to markdown unless JSON is requested.
Success Example
# Rover A2W run

Status: running
Run: https://agent.rtrvr.ai/v1/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/v1/a2w/runs/a2w_run_123?access=a2w_access_...&format=markdown&wait=10

Notes

  • 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`.
GET/v1/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.
POST/v1/a2w/runs/{id}

Continue a run that is waiting on user input.

Auth: Run access token.

Required Request Fields

FieldTypeDescription
inputstringUser or agent continuation answer.
DELETE/v1/a2w/runs/{id}

Cancel an in-flight A2W run.

Auth: Run access token.

POST/v1/a2w/runs/{id}/handoffs

Create a delegated child run on another Dayside-enabled site and keep the same workflow lineage.

Auth: Parent run access token.

Required Request Fields

FieldTypeDescription
urlstringTarget Dayside-enabled site URL.

Optional Request Fields

FieldTypeDescription
instructionstringDelegation instruction for the target site.
goalstringCanonical goal for the delegated child run.
shortcutIdstringExact shortcut to run on the receiving site.
capabilityIdstringExplicit child-run capability identifier.
argsRecord<string, unknown>Structured arguments for the delegated capability.
target{ pageId?, route?, capabilityId?, entityId?, formId? }Optional page/entity/form targeting hints on the receiving site.
identity{ userPresent?, signature?, signatureInput?, verificationMethod? }Structured user-presence and verification hints for the child run.
execution{ mode?: 'cloud' | 'browser' | 'device' | 'auto'; userPresent?: boolean }Requested execution path for the child run; `device` maps to browser/on-device execution.
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?, name?, vendor?, model?, version?, homepage? }Optional child-run agent identity override. If omitted, the current visiting-agent attribution is inherited.
contextSummarystringStructured summary to carry into the child run.
expectedOutputstringDescribe what the child should return to the parent workflow.

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.
GET/v1/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 Dayside Workspace for key lifecycle and site config management. These remain Firebase-authenticated control-plane endpoints.

Cloud site config persists shortcuts, business type, sparse Dayside 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.

POST/generateRoverSiteKey

Create a new site key and persisted policy/profile.

Auth: Firebase ID token (Bearer)

Required Request Fields

FieldTypeDescription
siteId | siteNamestringExisting siteId or a siteName for server-generated siteId.
labelstringHuman-readable key label.
allowedDomainsstring[]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

FieldTypeDescription
ttlDaysnumberExpiration days, use 0 for no expiry.
environment'production' | 'development' | 'test'Deployment environment label.
capabilities{ roverEmbed?, externalWebContextScrape?, cloudAgent?, cloudScrape? }Capability profile for this key.
roverPolicyRoverSitePolicyPolicy persisted and returned in list/replace APIs, including `siteMode`, `domainScopeMode`, `cloudSandboxEnabled`, mascot settings, and shortcut limits.
POST/listRoverSiteKeys

List all site keys for the authenticated workspace user.

Auth: Firebase ID token (Bearer)

POST/updateRoverSiteKeyPolicy

Patch a key's allowed domains, active status, capabilities, and site policy.

Auth: Firebase ID token (Bearer)

Required Request Fields

FieldTypeDescription
keyIdstringTarget key identifier.

Optional Request Fields

FieldTypeDescription
siteIdstringOptional site assertion/update.
allowedDomainsstring[]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.
activebooleanEnable/disable key.
capabilitiesApiKeyCapabilitiesCapability patch.
roverPolicyPartial<RoverSitePolicy>Policy patch, including `siteMode`, `domainScopeMode`, `cloudSandboxEnabled`, mascot settings, and shortcut limits.
POST/rotateRoverSiteKey

Rotate a key (invalidate old key and issue a new pk_site_* value).

Auth: Firebase ID token (Bearer)

Required Request Fields

FieldTypeDescription
keyIdstringKey being rotated.

Optional Request Fields

FieldTypeDescription
siteIdstringOptional site assertion/update.
labelstringOptional new label.
capabilitiesApiKeyCapabilitiesCapability patch applied to rotated key.
roverPolicyPartial<RoverSitePolicy>Policy patch applied to the replacement key, including `siteMode`, `domainScopeMode`, `cloudSandboxEnabled`, mascot settings, and shortcut limits.
POST/deleteRoverSite

Delete a site, all owned site keys, and Dayside-owned config while retaining historical analytics.

Auth: Firebase ID token (Bearer)

Required Request Fields

FieldTypeDescription
siteIdstringSite identifier to delete.

Notes

  • Deletes all owned site keys for the site, plus Dayside-owned site config and analytics owner settings/questions.
  • Historical analytics, visits, reviews, interviews, notes, posts, and aggregates are retained.
  • Webflow-managed sites are detached from the live managed Webflow install before Dayside-owned resources are removed.
POST/getRoverSiteConfig

Read 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

FieldTypeDescription
keyIdstringSite key ID.

Optional Request Fields

FieldTypeDescription
siteIdstringOptional site assertion.
POST/upsertRoverSiteConfig

Write cloud shortcuts, business type, sparse experience overrides, greeting, voice, AI access, discovery, and page-capture config.

Auth: Firebase ID token (Bearer)

Required Request Fields

FieldTypeDescription
keyIdstringSite key ID.

Optional Request Fields

FieldTypeDescription
siteIdstringOptional site assertion.
siteConfig.shortcutsRoverSiteShortcut[]Persisted shortcuts/journeys.
siteConfig.businessTypeRoverBusinessTypeTunes runtime placeholder hints and generated quick actions when the site has few explicit shortcuts.
siteConfig.experienceRoverSiteExperience | nullSparse Dayside 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? } | nullGreeting config.
siteConfig.voice{ enabled?: boolean; language?: string; autoStopMs?: number } | nullBrowser dictation config. autoStopMs is the post-speech silence window in milliseconds. Use null to clear persisted voice settings.
siteConfig.aiAccessRoverSiteAiAccess | nullPublic 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' } } | nullPer-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.agentDiscoveryRoverSiteAgentDiscovery | nullPersisted public discovery policy, well-known artifact paths, host-surface binding, and seed/presence-led display settings. Use null to clear.
siteConfig.pageConfigRoverPageCaptureConfig | nullSparse per-site page-capture overrides. New generated installs default disableAutoScroll to true; use null to clear overrides.
POST/updateApiKeyCapabilities

Patch capability flags for user or site keys.

Auth: Firebase ID token (Bearer)

Required Request Fields

FieldTypeDescription
keyIdstringTarget key identifier.
capabilitiesApiKeyCapabilitiesBoolean capability patch fields.

Analytics Workspace Data Paths

Analytics pages 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. The roverbook_* collection names are wire names kept for protocol compatibility.

READFirestore: roverbook_* collections

Owner-facing analytics 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.
POSTgetRoverBookInteractionDetail

Hydrate one analytics interaction detail, including Storage-backed trajectory data, after owner access is verified.

Auth: Firebase ID token (owner only).

Required Request Fields

FieldTypeDescription
siteIdstringOwned site identifier.
interactionIdstringAnalytics interaction identifier.

Notes

  • Workspace uses this for on-demand detail drawers so browser clients never read `roverbook-interactions/...` Storage blobs directly.
POSTgetRoverBookNotificationSettings

Read the private analytics setup payload for a site, including interview questions and masked webhook subscriptions.

Auth: Firebase ID token (owner only).

Required Request Fields

FieldTypeDescription
siteIdstringOwned site identifier.
POSTupsertRoverBookNotificationSettings

Write analytics interview questions and webhook subscriptions for a site.

Auth: Firebase ID token (owner only).

Required Request Fields

FieldTypeDescription
siteIdstringOwned site identifier.

Optional Request Fields

FieldTypeDescription
enabledbooleanEnable or disable analytics outbound notifications for the site.
webhooksRoverAnalyticsWebhookSubscription[]Private per-site webhook subscription list.
interviewQuestionsstring[]Per-site 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.
POSTupsertRoverBookQuestions

Write just the analytics interview questions for a site.

Auth: Firebase ID token (owner only).

Required Request Fields

FieldTypeDescription
siteIdstringOwned site identifier.
interviewQuestionsstring[]Per-site analytics interview prompts.

Runtime APIs (/v2/rover/*)

Server-authoritative runtime contract for embedded Dayside. All run-state changes are keyed by sessionId + runId + epoch + seq.

POST/v2/rover/session/open

Bootstrap 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

FieldTypeDescription
siteIdstringWorkspace site identifier.
host | urlstringCurrent host/url for domain and policy checks.
bootstrapToken | publicKeystringPublic site key (pk_site_*). Required when no valid sessionToken is supplied.

Optional Request Fields

FieldTypeDescription
sessionIdstringClient session identifier (auto-generated if omitted).
sessionTokenstringCurrent rvrsess_* token. If invalid/expired and bootstrap token exists, server falls back to bootstrap flow.
Success Example
{
  "success": true,
  "data": {
    "sessionId": "visitor-123",
    "sessionToken": "rvrsess_...",
    "sessionTokenExpiresAt": 1771484403000,
    "streamToken": "rvrsess_...",
    "epoch": 5,
    "capabilities": { "roverEmbed": true },
    "policy": {
      "domainScopeMode": "registrable_domain",
      "cloudSandboxEnabled": true,
      "externalAllowDomains": [],
      "externalDenyDomains": []
    },
    "projection": { "sessionId": "visitor-123", "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

Example 1
{
  "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."
  }
}
Example 2
{
  "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 Dayside's built-in tab behavior instead of owner-selected tab overrides.
POST/v2/rover/session/open

Refresh an existing rvrsess_* token and SSE URL.

Auth: sessionToken

Required Request Fields

FieldTypeDescription
sessionIdstringSession to refresh (defaults to token sid).

Notes

  • Use when token is near expiry or after SSE auth failures.
POST/v2/rover/command

Submit user input and create/continue an authoritative run.

Auth: sessionToken

Required Request Fields

FieldTypeDescription
sessionIdstringTarget session.
messagestringUser message.
expectedEpochnumberRequired in strict mode for stale-epoch protection.
clientEventIdstringIdempotency key for retries and dedup.

Optional Request Fields

FieldTypeDescription
continueRunbooleanContinue active run. Reserved for ask_user answer continuation in the same task boundary.
forceNewRunbooleanCancel active run and create a fresh run. Normal user sends should set this true.
expectedSeqnumberRequired in strict mode when active run exists.
requestedMode'act' | 'planner' | 'auto'Routing preference. `act`/`planner` force backend mode; `auto` uses heuristic routing.
taskBoundaryIdstringOptional client task boundary identifier.
Success Example
{
  "success": true,
  "data": {
    "runId": "run-uuid",
    "acceptedMode": "act",
    "state": "running",
    "continuePrompt": false,
    "requestedMode": "act",
    "epoch": 5,
    "seq": 1
  }
}

Typed Conflict/Auth Errors

Example 1
{
  "success": false,
  "error": "stale_epoch",
  "data": {
    "sessionId": "visitor-123",
    "runId": "run-uuid",
    "expectedEpoch": 2,
    "currentEpoch": 5,
    "decisionReason": "stale_epoch_retryable",
    "conflict": { "type": "stale_epoch", "currentEpoch": 5, "retryable": true }
  }
}
Example 2
{
  "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.
POST/v2/rover/command

Control run lifecycle (`cancel`, `end_task`, `new_task`, `continue`).

Auth: sessionToken

Required Request Fields

FieldTypeDescription
sessionIdstringTarget session.
action'cancel' | 'end_task' | 'new_task' | 'continue'Requested run control action.
expectedEpochnumberRequired in strict mode.
clientEventIdstringIdempotency key.

Optional Request Fields

FieldTypeDescription
runIdstringRequired for `cancel` and `end_task` when active run is not implied.
expectedSeqnumberStrict stale-seq guard for run-scoped actions.
reasonstringAudit reason for control action.
Success Example
{
  "success": true,
  "data": {
    "action": "cancel",
    "runId": "run-uuid",
    "currentSeq": 18,
    "projection": { "sessionId": "visitor-123", "epoch": 6, "activeRunId": "", "events": [], "tabs": [] }
  }
}

Notes

  • Use clientEventId for idempotent retries.
  • Strict mode requires expectedEpoch and enforces stale rejection before state transitions.
POST/v2/rover/command

Submit navigation/tab intent and receive authoritative policy decision.

Auth: sessionToken

Required Request Fields

FieldTypeDescription
sessionIdstringTarget session.
targetUrl | urlstringNavigation destination.
expectedEpochnumberRequired in strict mode.
clientEventIdstringIdempotency key used for silent retry recovery.

Optional Request Fields

FieldTypeDescription
runIdstringIntended active run (defaults to session active run).
expectedSeqnumberStrict stale-seq guard for run-scoped events.
currentUrlstringCurrent browser URL.
currentHost/targetHost/isCrossHost/navigationClasshintsClient hints. Server computes authoritative class regardless.
logicalTabIdstringLogical tab identifier for run tab graph.
messagestringPrompt context used for adversarial scoring.
adversarialScorenumberOptional explicit score (merged with server score).
Success Example
{
  "success": true,
  "data": {
    "decision": "allow_same_tab",
    "decisionReason": "allow_same_tab",
    "decisionHint": "allow_same_tab",
    "notice": "In-scope navigation allowed.",
    "staleRun": false,
    "sessionId": "visitor-123",
    "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

Example 1
{
  "success": false,
  "error": "stale_seq",
  "data": {
    "sessionId": "visitor-123",
    "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 }
  }
}
Example 2
{
  "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).
GET/v2/rover/stream

SSE stream for projection updates and keepalive pings.

Auth: sessionToken (query/body)

Required Request Fields

FieldTypeDescription
sessionIdquery stringSession to stream.

Optional Request Fields

FieldTypeDescription
seqAfternumberStart events after this sequence.

Notes

  • SSE events: `ready`, `projection`, `ping`, `error`.
  • Use GET /v2/rover/state as polling fallback.
GET/v2/rover/state

Fetch latest projection (session/run/tabs/events/snapshot metadata).

Auth: sessionToken

Required Request Fields

FieldTypeDescription
sessionIdquery/bodySession to fetch.

Optional Request Fields

FieldTypeDescription
seqAfternumberReturn events after this sequence only.
POST/v2/rover/snapshot

Upsert 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

FieldTypeDescription
sessionIdstringTarget session.
checkpoint | payloadobjectCompacted snapshot payload.

Optional Request Fields

FieldTypeDescription
visitorIdstringVisitor ID for checkpoint ownership.
updatedAtnumberClient timestamp in ms.
versionnumberSnapshot schema version.
seqnumberLast stable seq captured in snapshot.
compactedPrevStepsunknown[]Compacted execution history.
chatSummarystringConversation summary text.
ttlHoursnumberTTL for snapshot document.
POST/v2/rover/context/external

Fetch/act on external context through policy-scoped cloud integrations.

Auth: sessionToken

Required Request Fields

FieldTypeDescription
sessionIdstringTarget session.
runIdstringActive run ID.
urlstringExternal target URL.
intent'open_only' | 'read_context' | 'act'External action intent.
expectedEpochnumberStrict stale-epoch guard.
expectedSeqnumberStrict stale-seq guard.

Optional Request Fields

FieldTypeDescription
logicalTabIdstringLogical external tab id.
message | userInputstringUsed for adversarial gating and context.
timeoutMsnumberExternal 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.
POST/v2/rover/telemetry/ingest

Ingest runtime telemetry batches (diagnostics/observability).

Auth: sessionToken

Required Request Fields

FieldTypeDescription
sessionIdstringTarget session.
eventsunknown[]Telemetry event batch (server truncates to safe limits).

Optional Request Fields

FieldTypeDescription
runIdstringActive run association.
flushReasonstringFlush reason (`interval`, `manual`, etc.).
pageUrlstringCurrent page url.
sampleRatenumberClient telemetry sample rate.
sdkVersionstringSDK 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

RoverSuccessResponse<T>
type RoverSuccessResponse<T> = {
  success: true
  data: T
}
RoverErrorResponse
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
    }
  }
}
TabEventDecisionResponse
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[] }
}>
RunInputResponse
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 }
}>
RunControlResponse
type RunControlResponse = RoverSuccessResponse<{
  action: 'cancel' | 'end_task' | 'new_task' | 'continue'
  runId?: string
  currentSeq?: number
  projection: SessionProjectionResponse
}>
RunTransitionPayload
type RunTransitionPayload = {
  runId: string
  status: 'queued' | 'running' | 'awaiting_user' | 'cancel_requested' | 'cancelled' | 'completed' | 'failed'
  continuationReason?: 'loop_continue' | 'same_tab_navigation_handoff' | 'awaiting_user'
}
SessionProjectionResponse
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
}
SSE Event Shape
// GET /v2/rover/stream emits:
// event: ready      data: { sessionId, ts }
// event: projection data: SessionProjectionResponse
// event: ping       data: { ts }
// event: error      data: { message }
Public A2WRun
type A2WRun = {
  id: string
  protocol?: 'a2w'
  runId: string
  run: string
  status: 'pending' | 'waiting_browser' | 'running' | 'input_required' | 'completed' | 'failed' | 'cancelled' | 'expired'
  open?: string
  input?: { questions?: unknown[]; message?: 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>[]
  }
}
Public A2W Event Shape
// GET /v1/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_seq when expectedSeq is stale/missing (strict mode) for mutable run-scoped calls.
  • 409 stale_epoch when expectedEpoch is stale/missing (strict mode) for mutable calls.
  • 409 active_run_exists on concurrent run creation races (typed conflict, no generic unknown error).
  • 200 decision='stale_run' for non-fatal stale/missing run in POST /command with type='TAB_EVENT'.
  • If command-based tab preflight is temporarily unavailable, the SDK falls back to local smart-tab checks instead of hard-blocking navigation.
  • 401 SESSION_TOKEN_EXPIRED, 401 SESSION_TOKEN_INVALID, and 401 BOOTSTRAP_REQUIRED for typed auth flows.

Run Lifecycle and Continuity Semantics

  • Hard invariant: one active run per session, enforced in backend store/ledger.
  • requestedMode in POST /command payloads with type='RUN_INPUT': act and planner force backend mode; auto uses heuristic routing.
  • SDK default: normal user sends are fresh task boundaries with forceNewRun=true (fresh prevSteps + tab scope).
  • continueRun=true is used only for ask_user answer submission on the active boundary.
  • Heuristic follow-up chat carryover is cue-only (followupChatLog in 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; the SDK should perform one silent retry for command-based tab stale conflicts.