Errors
Every endpoint returns one of two response shapes.
Success
{ "data": { ... } }List endpoints add pagination metadata at the top level:
{
"data": [...],
"total": 150,
"page": 1,
"limit": 20,
"meta": { "pages": 8 }
}Failure
{
"error": "human-readable message",
"details": { "fieldErrors": { "fullName": ["required"] } }
}details is optional — present for validation errors (Zod field-level breakdown), absent for most other failures.
Status codes
| Status | Meaning | What to do |
|---|---|---|
| 200 | OK | Use data |
| 201 | Created | Use data (resource ID lives in data.id) |
| 202 | Accepted (async) | Use data.id (or data.jobId) to poll, or subscribe to webhooks |
| 400 | Validation failed | Read details.fieldErrors — fix the request and retry |
| 401 | Unauthorized | Missing/invalid auth — re-issue the key |
| 403 | Forbidden | Auth valid but lacks scope or org capability — see error message |
| 404 | Not found | Resource doesn't exist or isn't in your org |
| 409 | Conflict | State machine rejected — read message, fix state, retry |
| 413 | Payload too large | Body or file exceeded the documented size cap |
| 415 | Unsupported media type | Use application/json or multipart/form-data as documented |
| 422 | Business rule violated | Action makes sense syntactically but is blocked by business logic |
| 429 | Rate limited | Honour the Retry-After header, then retry with exponential backoff |
| 500 | Server error | Transient — retry with exponential backoff. Persists? File a support ticket |
| 503 | Service unavailable | Upstream (DB/Redis) degraded — see Status, retry after a moment |
Common error codes
A few error strings you'll see across products:
| Error | Meaning |
|---|---|
missing or invalid Bearer | No Authorization header or malformed prefix |
missing scope: <scope> | Key lacks the required scope |
validation failed | Request body failed schema validation (see details) |
rate limit exceeded | Per-key or per-org throttle hit |
org capability disabled | Endpoint is gated by a per-org capability you don't have |
replay detected | Idempotency conflict — same signature seen recently |
not found | Resource ID isn't in your org's scope |
state conflict: cannot transition X → Y | State machine rejected the action |
four-eyes violation: drafter cannot submit | Approval workflow blocked self-approval |
Retry strategy
Recommended client behaviour
- 400, 401, 403, 404, 409, 422: do not retry. Fix the request.
- 429: read
Retry-After(seconds). Wait. Retry once. If hit again, back off exponentially. - 500, 502, 503, 504: exponential backoff with jitter:
min(2^n + jitter, 60s). Cap at 5 retries. - Network errors / timeouts: same as 5xx — backoff with jitter.
Idempotency
For POST endpoints, pass your own externalId to make retries safe:
POST /api/screenings
{
"externalId": "loan-application-2026-05-24-001",
"fullName": "Budi Santoso",
...
}If we see the same externalId within the de-dup window (24 hours by default), we return the original response instead of creating a duplicate resource. The response includes "idempotent": true so you know it's a replay.
Reporting bugs
Found a real bug (not a 4xx)? Email developers@quantumelixir.tech with:
- The
x-quantum-request-idheader value from the response. We use this to find your request in our logs. - The full request (with the API key redacted).
- The full response (status, headers, body).
We aim to triage within one business day.