Overview

Every code you can receive, what it means, and whether retrying helps.

Two rules make the rest of this page readable.

Every error carries a code. The HTTP status says what kind of problem it is; the code says which one. Branch on the code — statuses are shared, codes are not.

json
{
  "error": "QUOTA_EXCEEDED",
  "detail": "this organisation does not have enough credits for that call",
  "context": { "balance": "0", "needed": "1", "limit": "20", "used": "20", "plan": "free" },
  "request_id": "01J…"
}
Field Meaning
error The code. Stable — safe to branch on
detail Plain language. Not stable; do not match on it
context Whatever is useful for this code. Shape varies
request_id Quote this when you ask us about a call

A refusal is not an error. An oracle that ran and refused answers 200 with "status": "invalid". See Verdicts.

Codes

Status Code Meaning Retry?
401 KEY_MISSING No bearer token was sent After fixing the header
401 KEY_UNKNOWN The token is not recognised No — check for a truncated paste
401 KEY_REVOKED The key was revoked Never. Mint a new one
401 KEY_EXPIRED The key passed its expiry Never. Mint a new one
403 ORG_DISABLED The key is fine; its organisation is not active No. Keep the key and contact support
400 SIGNATURE_INVALID A figure token is malformed, altered or expired No — draw from a fresh answer
402 QUOTA_EXCEEDED The allowance is spent When the window turns, or on a bigger plan
404 NOT_FOUND No such oracle, or no organisation for this key No — read GET /v1/oracles
422 VALIDATION_FAILED The request is malformed, or the format is one this oracle cannot produce After correcting it. context.available lists the formats
422 DATA_REQUIRED A chart request does not give the values to draw After putting them in the intent, or with allow_generated_data
500 INTERNAL Something failed that we did not anticipate Yes, once. Then send us the request_id
501 UNSUPPORTED Nothing draws this figure's target No
503 UPSTREAM_UNAVAILABLE A service the call depends on is briefly unavailable Yes, after a short wait
200 — "status": "error" — our fault Yes. Nothing was billed

That is the whole list. A request that fails validation names the field in context.parameter. Each endpoint's page lists exactly which of these it can return.

The distinctions worth honouring

402 is not 401. Your credential is fine; the allowance is spent. A client that treats a spent quota as an auth failure re-prompts for a key that was never the problem — often to a human, in the middle of the night.

ORG_DISABLED is 403, not 401. The key is fine; the organisation behind it is not active. A client that throws the key away and asks for a new one gets the same answer with the new one. Keep it, and tell a person.

KEY_REVOKED and KEY_EXPIRED are permanent. No amount of backoff will help. A client that retries these forever is a client that never tells anyone it is broken.

A 200 can still be a failure. "status": "error" is ours, and unbilled. Branch on status, not only on the status line.

See Handle every verdict for the client code.