error.code
rather than parsing prose or matching on status alone.
Codes
Every error links here, at the anchor for its own code.invalid_request
400 · A malformed body, a bad query parameter, or a missing Idempotency-Key on a
write. param names the offending field. Don’t retry — fix the request.
invalid_token
401 · The bearer token is missing, malformed, expired or revoked. All four are
reported identically so that probing can’t tell them apart. Issue a new token.
insufficient_scope
403 · The token doesn’t carry a scope the endpoint requires; requiredScopes lists
what would work. Retrying won’t help — see
403 can appear without your token changing.
not_found
404 · No such resource for this token. Also returned for a resource that exists but
belongs to another organization — see below.
method_not_allowed
405 · Known path, wrong method.
conflict
409 · The request contradicts current state: a duplicate email, an Idempotency-Key
reused with a different body, or a transition that no longer applies (reviewing
a reimbursement that someone already reviewed). Retrying the same call gives the
same answer.
rate_limited
429 · The token’s bucket for this minute is exhausted. Retry-After says how long to
wait. See Rate limits.
internal_error
500 · Our fault. It’s already reported to our error tracker along with the
requestId in your response. Retry with backoff.
provider_error
502 · An upstream provider — email, SMS, payments — rejected the call, so the
operation did not take effect. Safe to retry.
404 means “not visible to you”
A resource belonging to another organization returns404, not 403. Existence
is itself information: a 403 would confirm that an id is real, letting anyone
enumerate ids across organizations. This applies to chapters too — a national
reading a chapter that isn’t its direct child gets a 404.
403 can appear without your token changing
Effective permissions are re-derived on every request:insufficient_scope today because
your role was lowered, or because an admin blocked that scope for the whole
organization. Treat insufficient_scope as a condition to surface to a human,
not to retry.
Retrying safely
Retry429, 500 and 502 with exponential backoff and jitter. Do not retry
4xx other than 429 — the request will fail identically.
Every POST requires an Idempotency-Key, so a retry of a write is safe by
construction: reusing the key replays the original response instead of creating
a second record. See Idempotency.
Include
requestId when you contact support. It identifies the exact request
in our logs, including the endpoint, the token used and the failure.
