Errors
Every failed API call returns an RFC 9457 problem+json body with a stable error code, and every response carries an X-Request-Id header that ties the call to the server-side audit trail.
problem+json (RFC 9457)
Errors use the standard application/problem+json media type. Fields:
| Field | Meaning |
|---|---|
type | URI identifying the error type — stable across occurrences. |
title | Short human-readable summary (e.g. "Insufficient scope"). |
status | The HTTP status code, mirrored in the body. |
detail | Human-readable explanation of this occurrence. |
instance | The request path that produced the error. |
requestId | Server-generated ID matching the X-Request-Id response header. |
{
"type": "https://<host>/problems/auth_insufficient_scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This token does not include the exports:create scope.",
"instance": "/api/v1/studies/STUDY_ID/exports",
"requestId": "REQUEST_ID"
}Branch on type (or the error code it encodes), not on detail text — the detail string is for humans and may change; the type is a stable contract.
Error codes
| Code | Typical status | When it occurs | What to do |
|---|---|---|---|
auth_invalid_client | 401 | Client ID or secret is wrong at token exchange. | Check credentials; if the secret was rotated, use the current one. |
auth_invalid_token | 401 | Token missing, malformed, or expired. | Request a fresh token and retry once. |
auth_insufficient_scope | 403 | Token lacks a scope the call requires. | Request the scope at token time, or widen the client in the admin UI. |
rate_limited | 429 | Rate budget exhausted (see rate limits). | Back off per Retry-After, then retry. |
not_found | 404 | Resource does not exist or is outside your organization. | Verify the ID and org scoping. |
validation_failed | 400/422 | Request body or params fail schema validation. | Fix the fields listed in the error detail. |
conflict_etag | 409 | If-Match did not match the current ETag. | Re-read the resource, reapply your change, retry with the new ETag. |
idempotency_replayed | 409 | A used idempotency key was replayed with a different body. | Use a fresh key per logical operation; see pagination. |
phi_scope_required | 403 | PHI fields requested without the phi:read scope. | Request phi:read at token time if entitled, or work with the de-identified projection. |
Codes are also encoded in the type URI of the problem body, so integrations can switch on a stable identifier without parsing the title.
X-Request-Id
Every response — success or error — carries an X-Request-Id header, and the problem body mirrors it in requestId. When contacting support about a failed call, include the request ID: it pins down the exact request in the server-side audit trail and logs.
Status code summary
401— authentication problem (bad client, bad or expired token). See authentication.403— authorization problem (missing scope, PHI scope required). See authentication.404— resource does not exist or is outside your organization.409— concurrency conflict (ETag) or idempotency replay. See pagination.429— rate limited. See rate limits.