Every code
details appears on 400 INVALID_INPUT (naming the offending fields) and on
429 RATE_LIMITED (carrying the limit and reset). Treat it as diagnostic detail for
logs and developers, not something to parse into user-facing copy.
The ones worth designing for
404 is deliberately ambiguous
404 is deliberately ambiguous
A resource that doesn’t exist, one that belongs to another organization, and an id that
isn’t a UUID all return the identical
404. The API will not confirm that an id exists
somewhere you can’t see it.Practically: don’t treat 404 as “deleted”. It also means “never existed” and “not
yours”.402 means the plan quota is spent
402 means the plan quota is spent
Only
POST /v1/assessments/{id}/invitations can return it — quota is consumed when an
invitation is sent, not when an assessment is created.Surface it as an admin action (“your plan’s assessments for this period are used up”),
not as a retryable failure. Retrying returns 402 until the period rolls over or the
plan changes. Reproduce it in test mode by inviting limit@example.com.429 carries Retry-After
429 carries Retry-After
Honour the
Retry-After header (seconds) rather than inventing a backoff. details
also carries limit and reset if you’d rather compute your own.A 429 can also come from repeated failed authentication from your IP, in which case
it’s telling you to stop retrying a bad key.500 is ours, and needs a request id
500 is ours, and needs a request id
The body is deliberately generic — we don’t leak internals into responses. Everything
needed to diagnose it is in the
request_id, so log that and send it to us.Safe to retry with backoff. If it’s reproducible, it’s a bug; tell us.Suggested handling
There is no idempotency key yet, so a retried write can duplicate. Retrying a
timed-out invitation create may invite the candidate twice. Guard retries on your side
until idempotency ships.