Error Reference

All errors follow RFC 7807 Problem Details format:

{
  "type": "https://api.roveapi.com/errors/invalid-api-key",
  "title": "Invalid API key",
  "status": 401,
  "detail": "A valid API key is required. Pass it as: Authorization: Bearer rvp_live_...",
  "instance": "/v1/browser/session"
}

Authentication Errors

invalid-api-key (401)

API key is missing, malformed, revoked, or not found in the database.

Common causes:

  • Missing Authorization header
  • Key doesn't start with rvp_live_ or rvp_test_
  • Key was revoked via the dashboard or API
  • Typo in the key

Fix: Check that you're passing the full key as Authorization: Bearer rvp_live_xxxx.... Keys are 41 characters long.


test-key-not-allowed (403)

A test key (rvp_test_) was used on an endpoint that requires a live key.

Fix: Use your live key (rvp_live_) for this request.


supervised-live-key-required (400)

A test key requested a supervised browser session. Test keys use deterministic mock actions and never allocate a streamable browser.

Fix: Run the MCP authenticate tool to obtain a live key, or provide an existing rvp_live_ key.


device-auth-email-unavailable (503)

Rove's email provider did not accept the authentication message. No pollable request remains after this response.

Fix: Retry later or provide an existing rvp_live_ key.


device-auth-rate-limited (429)

The authentication email quota for the source IP or normalized recipient address was reached.

Response includes: Retry-After: 900

Fix: Wait 15 minutes before requesting another authentication email.


live-key-required (403)

A test key attempted to create a live API key. Test keys cannot escalate their own privileges.

Fix: Run the MCP authenticate tool with a verified email or use an existing live key.


device-auth-approval-unavailable (503)

Rove accepted the email verification but could not atomically finish customer and API-key provisioning. The claim is restored when safe so the same link can be retried.

Fix: Retry the verification link. If it remains unavailable, start authentication again.


Billing Errors

Problem types: match a problem by the last path segment of type, never by host. Older problems use https://api.noncelogic.com/errors/...; billing problems use https://api.roveapi.com/errors/....

Billing problems carry these members:

  • retry: same_key (repeat the request, with the same Idempotency-Key, after Retry-After when present), new_key (this attempt is over; a new attempt needs a new key) or none (repeating it fails until something changes).
  • owner_action_url: where a person (the account owner) can act, when only they can.
  • idempotency_key when the request had one, and purchase_id when a purchase exists.

Status 402 has two types: insufficient-credits (the balance is too low for an operation) and payment-failed (a purchase's payment failed). Branch on the type, not the status.

insufficient-credits (402)

Your credit balance is too low for the requested operation. Type https://api.noncelogic.com/errors/insufficient-credits.

The problem also carries the out-of-credits extensions (left out when the balance cannot be read):

MemberMeaning
credits_remaining, credits_remaining_millicreditsThe balance, whole and exact
required_millicreditsWhat the refused operation needed
packs_within_limitsPack ids this key may buy now within every limit
purchasingallowed, and reason (agent_purchasing_off or key_not_granted) when not
next_stepbuy_credits or ask_owner
linksbalance, purchase, catalogue, docs
owner_action_urlThe billing page where the owner adds credits
retrynone

Fix: When next_step is buy_credits, buy a pack from packs_within_limits (Billing API). Otherwise give owner_action_url to the account owner, or switch to a test key for development. Credit packs:

PackPriceCredits
1,000 credits$101,000
5,000 credits$495,000
10,000 credits$8910,000

A supervised session that runs out ends with 410 session-expired and reason: "credit_exhausted", carrying the same extensions without required_millicredits. Example bodies: Out of credits.

payment-failed (402)

A purchase's payment failed: the saved card was declined under payment: "saved_method", or Stripe refused the charge. The purchase is failed and nothing was charged. Carries failure_code and purchase_id; retry is new_key.

Fix: Try again with a new Idempotency-Key, for example with payment: "checkout" to get a payment link.

Purchase errors

From POST /v1/billing/purchases and the other /v1/billing/purchases routes. How to retry each is in Idempotency and retries.

TypeStatusMeaning and fixretry
idempotency-key-required400Send an Idempotency-Key header.none
invalid-cursor400The listing cursor is not valid for this key. Restart the listing.none
purchase-not-permitted403reason: agent_purchasing_off or key_not_granted: only the account owner can allow this key to buy, at owner_action_url.none
purchase-not-permitted403reason: no_saved_method or off_session_not_allowed (only for payment: "saved_method"): retry with suggested_payment (auto), which gives a person a payment link.same_key
spend-limit-exceeded403A limit would be exceeded: limit (per_purchase, key_period, account_period), limit_cents, committed_cents, requested_cents, resets_at. Buy a pack in packs_within_limits, wait until resets_at, or give the owner owner_action_url.none
test-key-required403simulate is only for test keys.none
pack-not-found404No credit pack with this item_id is on sale. Read the catalogue again.none
purchase-not-found404No purchase with this id was made by this key.none
purchase-not-cancelable409Only a purchase waiting for payment can be canceled; purchase_status is its state.none
invalid-transition409A test purchase cannot be simulated to that outcome from purchase_status.none
idempotency-in-progress409The account's other purchase is being created. Wait Retry-After (1 second), repeat.same_key
idempotency-key-reused422The key was used for a different request. Use a new key.new_key
purchase-rate-limited42910 purchases per key or 20 per account in the last hour. Wait Retry-After.same_key
billing-unavailable503Billing could not reach Stripe or the database. Wait Retry-After, repeat with the same key; a kept purchase (purchase_id) is never charged twice.same_key

Billing page and owner errors

These come from the account billing routes (/v1/account/billing/...), which use the signed-in owner session, not an API key.

TypeStatusMeaning and fix
owner-session-required401Sign in again; owner_action_url says where.
owner-origin-refused403Billing changes are accepted only from the Rove web app.
key-not-found404No key with this id is on your account. Re-read your keys.
no-saved-method404There is no saved card to remove.
pack-not-found404No credit pack with this item_id is on sale. Read the catalogue again.
purchase-not-found404No purchase with this id belongs to your account.
purchase-not-cancelable409Only a purchase waiting for payment can be canceled. purchase_status is the purchase's state, or completing when the payment is already going through.
auto-topup-precondition409Auto top-up cannot be armed; reason is the first unmet condition: no_saved_method, off_session_not_allowed, purchasing_off, item_retired or exceeds_per_purchase_limit.
subscription-exists409The account already has a live subscription; change it in the billing portal.
billing-settings-rate-limited42930 billing-settings changes per account per hour. Wait Retry-After.
purchase-rate-limited429Too many purchases or billing requests. Wait for Retry-After.
billing-unavailable503Billing could not reach Stripe or the database. Nothing was charged. Retry after Retry-After.

Rate Limiting

rate-limit-exceeded (429)

Too many requests in the current time window.

Response includes:

Retry-After: 12
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1712134800

Fix: Wait until the Retry-After seconds elapse, then retry. Consider spacing out requests or upgrading your plan for higher limits.

PlanRequests/min
Pay as you go10
Builder60
Scale300

Accounts on an earlier plan keep the limits they had.


Session Errors

session-not-found (404)

The session ID doesn't exist or has already been closed.

Fix: Create a new session via POST /v1/browser/session. Sessions are not reusable after closing.


session-expired (410)

Session exceeded the 30-minute inactivity timeout, or a supervised session has ended.

For a supervised session that has ended and that the API no longer holds in memory (for example after an API restart), POST /v1/browser/action and GET /v1/browser/session/{session_id} return this problem with two extra members:

  • reason: why the session ended.
    • runtime_restarted: Rove restarted. The browser ran inside the restarted process, so the session could not continue. Any human control was returned to the agent.
    • explicit_close: the session was closed with close_session or the viewer's Stop.
    • inactivity_expired: the session reached its idle or hard deadline.
    • credit_exhausted: the account ran out of credits. The browser profile is kept; add credits, then create a new session. This answer also carries the out-of-credits extensions (credits_remaining, credits_remaining_millicredits, packs_within_limits, purchasing, next_step, links, owner_action_url, retry: "none"), as on insufficient-credits; see the example body.
  • controller: who held control when it ended (agent or human). After a restart this is agent.
{
  "type": "https://api.noncelogic.com/errors/session-expired",
  "title": "Session expired",
  "status": 410,
  "detail": "Rove restarted, so this supervised session ended and control returned to the agent. Create a new session.",
  "instance": "/v1/browser/action",
  "reason": "runtime_restarted",
  "controller": "agent"
}

Behaviour change: these calls used to return 404 foreign-or-absent once the API no longer held the session. A session id that is unknown, or that belongs to another account or key, still returns 404.

Fix: Create a new session. To prevent expiry, ensure actions are sent at least every 30 minutes.


pool-exhausted (503)

No browser contexts available — all slots are in use.

Response includes:

Retry-After: 5

Fix: Wait and retry. This is temporary — contexts free up as other sessions close. If persistent, you may be hitting your concurrent session limit.


Browser Errors

Page failed to load within the timeout window (default: 30 seconds).

Common causes:

  • Target site is slow or unresponsive
  • DNS resolution failure
  • Site blocks automated browsers

Fix: Increase timeout_ms in the navigate params, or check that the URL is accessible.


selector-not-found (422)

CSS selector returned no matching elements on the page.

Fix: Verify the selector exists on the page. Use get_a11y_tree first to see what elements are available, then target by accessible label instead of CSS selector.


browser-crash (503)

The Chromium process terminated unexpectedly.

Fix: Create a new session and retry. This is rare but can happen with memory-intensive pages. If it happens consistently on the same page, try blocking images and fonts via block_resources: ["image", "font"] to reduce memory usage.


page-not-found (404)

No page with this page_id exists in the session.

Fix: Call list_pages.


page-closed (409)

That page has closed (for example, a sign-in popup that closed itself).

Fix: Call list_pages for the open pages.


last-page (409)

The last open page cannot be closed.

Fix: Navigate it, or close the session.


wait_for_popup found a popup that Rove blocked. reason is target-policy-refused (its address is not permitted in a supervised session: do not retry) or page-limit (8 pages are open: close one with close_page).


wait_for_popup saw no popup within timeout_ms.

Fix: Call get_a11y_tree; the last action may not open a popup.


invalid-action (400)

Unknown DSL action name.

Valid actions: navigate, get_a11y_tree, click, fill, select, scroll, wait_for, screenshot, get_text, get_attribute, evaluate, close_session


invalid-params (400)

Action parameters failed validation.

Fix: Check the Actions DSL reference for required parameters and types.


schema-extraction-failed (422)

Could not extract data matching the provided JSON schema.

Common causes:

  • Page hasn't finished loading — add wait_for_selector to the request
  • Schema field names don't match visible page content
  • Page structure has changed since the schema was written

Fix: Use get_a11y_tree or get_text first to verify the page content, then adjust your schema.

Rove — the supervised browser for agents