Errors
Every public failure is a real HTTP error with one flat body:
json
{
"error": "insufficient_scope",
"message": "This credential does not carry the required scope.",
"request_id": "server-issued-id",
"required": ["club.compliance.read"]
}error, message, and request_id are always present. Optional fields are only required, numeric code, and details (field/code pairs without submitted values). Match on error, never message text. The server issues request ids; caller-supplied ids are not trusted as identities.
| Status | Error |
|---|---|
| 400 | invalid_request |
| 401 | timestamp_out_of_window, signature_verification_failed, replay_detected, credential_revoked, credential_disabled, credential_expired |
| 403 | source_ip_not_allowed, insufficient_scope |
| 404 | not_found (also used for wrong workspace kind and foreign resources) |
| 409 | idempotency_key_in_progress, idempotency_key_reused, idempotency_outcome_unknown |
| 413 | payload_too_large (body ceiling: 100kb) |
| 429 | rate_limit_exceeded |
| 500 | internal_error |
Only explicitly approved internal INVALID_PARAMS and safe, workspace-fenced NOT_FOUND business failures are mapped. Every other internal, Prisma, or unexpected failure becomes internal_error; this disclosure boundary is fail closed.
See Idempotency before handling any of its 409 outcomes.