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
| HTTP | error.code | When |
|---|---|---|
| 401 | unauthorized | Missing / malformed / invalid / expired / revoked API key |
| 402 | insufficient_credits | (v2) Action would charge credits and the balance is empty |
| 403 | forbidden_scope | Authenticated but the key lacks the scope this route needs |
| 404 | not_found | No record matching the supplied id in this organisation |
| 409 | conflict | Resource collision (e.g. email already used by another customer) |
| 409 | idempotency_conflict | Idempotency-Key reused with a different request body |
| 422 | validation_failed | Request payload failed schema validation; see details.issues |
| 429 | rate_limited | Burst or daily limit exceeded; honour Retry-After |
| 500 | internal | Server-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:
When to retry
| Code | Retry? |
|---|---|
rate_limited | Yes — 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 |

