Skip to main content
All errors share a standard envelope:
{
  "error": {
    "code": "insufficient_credits",
    "message": "Organisation has insufficient credit balance.",
    "details": { "required": 15, "balance": 4 }
  }
}
  • error.code — stable, machine-readable identifier. Branch on this.
  • error.message — human-readable summary. Suitable for logs; safe to surface to your end users.
  • error.details — optional, code-specific extra fields.

Codes

HTTPerror.codeWhen
401unauthorizedMissing / malformed / invalid / expired / revoked API key
402insufficient_credits(v2) Action would charge credits and the balance is empty
403forbidden_scopeAuthenticated but the key lacks the scope this route needs
404not_foundNo record matching the supplied id in this organisation
409conflictResource collision (e.g. email already used by another customer)
409idempotency_conflictIdempotency-Key reused with a different request body
422validation_failedRequest payload failed schema validation; see details.issues
429rate_limitedBurst or daily limit exceeded; honour Retry-After
500internalServer-side error. Retry with backoff; contact support if persistent

not_found and cross-tenant isolation

A 404 not_found is returned both when the record genuinely doesn’t exist and when it belongs to a different organisation. This is deliberate — we never reveal whether an id belongs to another tenant. A guessed UUID from another org always returns 404, never data.

Validation errors

422 validation_failed includes per-field detail:
{
  "error": {
    "code": "validation_failed",
    "message": "Invalid customer payload.",
    "details": {
      "issues": {
        "email": ["Must be a valid email address."],
        "fullName": ["Must not be empty."]
      }
    }
  }
}
Surface these directly to the user who triggered the call.

When to retry

CodeRetry?
rate_limitedYes — after Retry-After seconds
internal (500)Yes — with exponential backoff
unauthorized (401)No — fix the key first
forbidden_scope (403)No — fix the scopes first
validation_failed (422)No — fix the payload first
conflict (409)No — resolve the collision
idempotency_conflict (409)No — use a fresh idempotency key or send the original body
not_found (404)No — the resource is not there