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
Authorizationheader - Key doesn't start with
rvp_live_orrvp_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, afterRetry-Afterwhen present),new_key(this attempt is over; a new attempt needs a new key) ornone(repeating it fails until something changes).owner_action_url: where a person (the account owner) can act, when only they can.idempotency_keywhen the request had one, andpurchase_idwhen 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):
| Member | Meaning |
|---|---|
credits_remaining, credits_remaining_millicredits | The balance, whole and exact |
required_millicredits | What the refused operation needed |
packs_within_limits | Pack ids this key may buy now within every limit |
purchasing | allowed, and reason (agent_purchasing_off or key_not_granted) when not |
next_step | buy_credits or ask_owner |
links | balance, purchase, catalogue, docs |
owner_action_url | The billing page where the owner adds credits |
retry | none |
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:
| Pack | Price | Credits |
|---|---|---|
| 1,000 credits | $10 | 1,000 |
| 5,000 credits | $49 | 5,000 |
| 10,000 credits | $89 | 10,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.
| Type | Status | Meaning and fix | retry |
|---|---|---|---|
idempotency-key-required | 400 | Send an Idempotency-Key header. | none |
invalid-cursor | 400 | The listing cursor is not valid for this key. Restart the listing. | none |
purchase-not-permitted | 403 | reason: agent_purchasing_off or key_not_granted: only the account owner can allow this key to buy, at owner_action_url. | none |
purchase-not-permitted | 403 | reason: 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-exceeded | 403 | A 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-required | 403 | simulate is only for test keys. | none |
pack-not-found | 404 | No credit pack with this item_id is on sale. Read the catalogue again. | none |
purchase-not-found | 404 | No purchase with this id was made by this key. | none |
purchase-not-cancelable | 409 | Only a purchase waiting for payment can be canceled; purchase_status is its state. | none |
invalid-transition | 409 | A test purchase cannot be simulated to that outcome from purchase_status. | none |
idempotency-in-progress | 409 | The account's other purchase is being created. Wait Retry-After (1 second), repeat. | same_key |
idempotency-key-reused | 422 | The key was used for a different request. Use a new key. | new_key |
purchase-rate-limited | 429 | 10 purchases per key or 20 per account in the last hour. Wait Retry-After. | same_key |
billing-unavailable | 503 | Billing 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.
| Type | Status | Meaning and fix |
|---|---|---|
owner-session-required | 401 | Sign in again; owner_action_url says where. |
owner-origin-refused | 403 | Billing changes are accepted only from the Rove web app. |
key-not-found | 404 | No key with this id is on your account. Re-read your keys. |
no-saved-method | 404 | There is no saved card to remove. |
pack-not-found | 404 | No credit pack with this item_id is on sale. Read the catalogue again. |
purchase-not-found | 404 | No purchase with this id belongs to your account. |
purchase-not-cancelable | 409 | Only 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-precondition | 409 | Auto 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-exists | 409 | The account already has a live subscription; change it in the billing portal. |
billing-settings-rate-limited | 429 | 30 billing-settings changes per account per hour. Wait Retry-After. |
purchase-rate-limited | 429 | Too many purchases or billing requests. Wait for Retry-After. |
billing-unavailable | 503 | Billing 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.
| Plan | Requests/min |
|---|---|
| Pay as you go | 10 |
| Builder | 60 |
| Scale | 300 |
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 withclose_sessionor 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 (agentorhuman). After a restart this isagent.
{
"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
navigation-timeout (504)
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.
popup-blocked (422)
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).
popup-timeout (504)
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_selectorto 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.