Skip to main content
Failures return a stable machine-readable code:
Switch on error.code, never on error.message. Codes are part of the contract; messages are written for humans and may be reworded without notice.

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

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”.
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.
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.
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.