rtrvr.ai logo
Roverby rtrvr.ai
Docs
Blog
Workspace
rtrvr.ai
Book Demo
Get Started

Getting Started

OverviewQuick Start

Integration

ConfigurationSecurity & Policies

Reference

API ReferenceExamples

API Reference

Complete Rover docs for workspace key management and browser runtime (`/v2/rover/*`) contracts.

Runtime base: https://extensionrouter.rtrvr.ai/v2/rover/*

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.

Workspace Management APIs

Used by Rover Workspace for key lifecycle and site config management. These remain Firebase-authenticated control-plane endpoints.

POST/generateRoverSiteKey

Create a new Rover 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).

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/rotate APIs.
POST/listRoverSiteKeys

List all Rover site keys for the authenticated workspace user.

Auth: Firebase ID token (Bearer)

POST/updateRoverSiteKeyPolicy

Patch a key's allowed domains, active status, capabilities, and Rover 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).
activebooleanEnable/disable key.
capabilitiesApiKeyCapabilitiesCapability patch.
roverPolicyPartial<RoverSitePolicy>Policy patch.
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 rotated key.
POST/getRoverSiteConfig

Read cloud journey/shortcut and greeting 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 journey/shortcut and greeting 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.greeting{ text?, delay?, duration?, disabled? } | nullGreeting config.
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.

Rover Runtime APIs (`/v2/rover/*`)

Server-authoritative runtime contract for embedded Rover. All run-state changes are keyed bysessionId + 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 Rover 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",
      "externalNavigationPolicy": "open_new_tab_notice",
      "crossHostPolicy": "same_tab",
      "enableExternalWebContext": true,
      "externalScrapeMode": "on_demand",
      "externalAllowDomains": [],
      "externalDenyDomains": []
    },
    "projection": { "sessionId": "visitor-123", "epoch": 5, "events": [], "tabs": [] },
    "siteConfig": { "shortcuts": [], "greeting": { "text": "Welcome" } },
    "sseUrl": "https://extensionrouter.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.
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 compacted checkpoint/snapshot for resume.

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>
  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 }

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, SDK falls back to local navigation policy 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; SDK should perform one silent retry for command-based tab stale conflicts.
Quick StartConfigurationOpen Workspace
rtrvr.ai logo
Rover

The first DOM-native embedded web agent. Clicks, fills, navigates, and onboards — through conversation.

Product

  • Overview
  • Workspace
  • Pricing

Developers

  • Quick Start
  • Configuration
  • API Reference
  • Security
  • Examples

Resources

  • Blog
  • rtrvr.ai Docs
  • rtrvr.ai Cloud

© 2026 rtrvr.ai. All rights reserved.

PrivacyTerms