API guides

Error codes

Every error returns the same envelope: an HTTP status, a stable machine code, and a human message. Branch on error.code, not the message text.

The error envelope
{
  "error": {
    "code": "invalid_api_key",
    "message": "The API key provided is invalid or has been revoked."
  }
}
Reference

The seven codes you'll meet

400

Bad Request

What it means — The request was malformed or a parameter failed validation — a wrong date format, an out-of-range latitude, an unknown spread name.

How to handle it — Read the detail field: it names the offending parameter and the expected shape. Validate client-side before retrying.

Example body
JSON
{
  "error": {
    "code": "validation_error",
    "message": "latitude must be between -90 and 90",
    "param": "latitude"
  }
}
401

Unauthorized

What it means — The X-API-Key header is missing, malformed, or the key was revoked. The request never reached the engine.

How to handle it — Check the header spelling (X-API-Key), confirm the key is active in Dashboard → API Keys, and rotate if it may have leaked.

Example body
JSON
{
  "error": {
    "code": "invalid_api_key",
    "message": "The API key provided is invalid or has been revoked."
  }
}
402

Payment Required

What it means — Your key is valid but the credit balance can't cover this call. Nothing was computed and nothing was charged.

How to handle it — Top up from Dashboard → Billing, then retry. Credits never expire and failed calls never deduct.

Example body
JSON
{
  "error": {
    "code": "insufficient_credits",
    "message": "This call needs 1 credit but your balance is 0.",
    "credits_needed": 1,
    "credits_balance": 0
  }
}
404

Not Found

What it means — The path doesn't exist — a typo'd endpoint, or a resource id (like a reading_id) that isn't yours or never existed.

How to handle it — Double-check the path against the reference. For resource ids, confirm the id came from a successful call with the same key.

Example body
JSON
{
  "error": {
    "code": "not_found",
    "message": "No reading found with id 9f2a1c4e-…"
  }
}
429

Too Many Requests

What it means — You exceeded 60 requests per minute on this key. The Retry-After header tells you exactly how long to wait.

How to handle it — Back off for Retry-After seconds, then retry. Add client-side pacing or request batching if you hit this often.

Example body
JSON
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Retry in 12 seconds.",
    "retry_after_seconds": 12
  }
}
500

Internal Server Error

What it means — Something broke on our side after your request passed validation. These are rare and always logged with a request id.

How to handle it — Retry with exponential backoff. If it persists, send us the x-request-id response header and we'll investigate.

Example body
JSON
{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred.",
    "request_id": "req_8f3ka2m9"
  }
}
503

Service Unavailable

What it means — A backing engine or model isn't ready yet — for example, interpretation content still loading after a deploy.

How to handle it — Treat like a 500: back off and retry. Deterministic computation endpoints are unaffected.

Example body
JSON
{
  "error": {
    "code": "engine_unavailable",
    "message": "The interpretation engine is warming up. Please retry shortly."
  }
}