Errors
The typed error envelope and the closed code registry — what to retry, what not to
Every error response, on every /v1 endpoint:
json
{"error": {"type": "billing_error", "code": "insufficient_credits",
"message": "Not enough credits for a standard run ($10).",
"param": null, "retriable": false,
"doc_url": "/developers/errors#insufficient_credits",
"request_id": "req_a1b2c3…"}}retriable answers the only question that matters mid-loop: can an identical
retry succeed? request_id is on every response (header X-Request-Id too) —
include it in support requests.
Code registry (closed)
| Code | HTTP | Retriable | Meaning / correct response |
|---|---|---|---|
invalid_request | 400 | no | malformed input — fix the request |
validation_failed | 422 | no | body failed validation; error.errors lists fields |
authentication_required / invalid_api_key | 401 | no | missing/bad key |
key_revoked / key_expired | 401 | no | a key we recognise that no longer works — mint or rotate a new one at /settings/api-keys |
key_suspended / account_suspended | 403 | no | the abuse guard paused this key / account (a runaway loop, off-purpose prompts). Stop and alert a human; do not mint a new key — a fresh key of a suspended user is refused too. Re-enable from /settings/api-keys or your support contact |
insufficient_role / insufficient_scope | 403 | no | key lacks the scope — mint one that has it |
workspace_forbidden | 403 | no | key can't act in that workspace |
not_found | 404 | no | unknown resource/entity |
conflict | 409 | no | state conflict (e.g. rotating a revoked key) |
no_active_blueprint | 409 | no | the workspace holds no Blueprint yet — design one at /onboarding or with POST /v1/blueprints/drafts. Returned by every endpoint that reads the workspace's schema: export, reports, report columns, and run listing |
idempotency_key_in_flight | 409 | yes | original still running — wait Retry-After |
idempotency_key_reused | 422 | no | same key, different payload — new key or same body |
rate_limited | 429 | yes | back off per Retry-After |
llm_daily_limit_exceeded | 429 | yes | the per-day cap on the free model surfaces (parsers, onboarding, chat) — a rate limit, not a billing wall: topping up does not lift it; retry after the window or ask support to raise it |
run_concurrency_exceeded | 429 | yes | your org's own run caps (set by your admin) — queue and retry |
insufficient_credits | 402 | no | balance too low — a human must top up |
plan_upgrade_required | 402 | no | the plan doesn't include this capability — topping up won't help; a human must upgrade |
budget_exceeded | 402 | no | this key's budget ceiling — a human must raise it |
payment_required | 402 | no | subscription required for this surface |
authorization_pending | 400 | yes | CLI sign-in not approved yet — keep polling at interval |
slow_down | 400 | yes | polling faster than interval — increase it, then continue |
expired_token | 400 | no | the device code expired or was already used — run deepsieve login again |
access_denied | 403 | no | the human refused the CLI sign-in |
internal_error | 500 | yes | our fault; retry with backoff |
service_unavailable | 503 | yes | transient; retry with backoff |
The four device codes belong to the CLI sign-in flow (CLI).
authorization_pending and slow_down are not failures — they are the
normal path while a human approves in their browser, which is why both are
retriable: true.
Additions to this registry are announced in the changelog; codes are never removed or renamed within v1.