All errors share one shape:
{
"error": {
"code": "conflict",
"message": "idempotencyKey was already used with a different payload",
"details": { "idempotencyKey": "order-1001-reward" },
"requestId": "f0e1d2c3-4b5a-6789-0abc-def012345678"
}
}
code — a stable machine-readable code (see below).
message — human-readable explanation.
details — optional structured context. For validation failures (bad_request) this
contains the specific field issues.
requestId — correlation id, also returned in the x-request-id header. Include it
when contacting support.
Status codes
| HTTP | code | Meaning |
|---|
| 400 | bad_request | Malformed JSON or failed validation (details lists the issues). |
| 401 | unauthorized | Missing or invalid x-api-key. |
| 403 | forbidden | Authenticated but not permitted. |
| 404 | not_found | Resource doesn’t exist (or belongs to another app). |
| 409 | conflict | Uniqueness conflict — duplicate email/externalId, or idempotency-key reuse. |
| 422 | unprocessable_entity | Semantically invalid request. |
| 500 | internal_error | Unexpected server error. |
| 502 | upstream_error | An upstream dependency failed. |
Branch on error.code, not the HTTP status or message text — codes are stable, messages may change.