Errors
The error response shape, what each status code means, and which ones are worth retrying.
The shape
Errors do not use the success envelope. They look like this:
{
"statusCode": 403,
"message": "Insufficient permissions. Required scopes: invoices:write",
"error": "Forbidden",
"timestamp": "2026-09-02T14:29:56.000Z",
"path": "/api/v1/invoices"
}Branch on statusCode, and show message — it is written to be read, and for scope and
validation failures it names the exact thing to fix. Do not parse message; it is
prose and may be reworded.
Status codes
| Code | Means | Retry? |
|---|---|---|
400 | The request is wrong — a missing field, a bad value, an unknown parameter, or a missing idempotency-key | No. Fix and resend. |
401 | The key is missing, invalid, revoked, expired — or its hourly rate limit is exhausted | Only if rate-limited; back off first. |
403 | Authenticated, but not allowed. A missing scope, another business's data, or an endpoint keys cannot reach | No. |
404 | No such resource — or the endpoint does not exist in this environment | No. |
409 | A conflict, such as an invoice number already used by this business | No. |
429 | More than 100 requests in a minute from your IP | Yes, after backing off. |
500 | Our fault | Yes, with backoff. Tell us if it persists. |
Validation errors
A 400 from a field validation names the field and the rule:
{
"statusCode": 400,
"message": ["At least one line item is required"],
"error": "Bad Request",
"timestamp": "2026-09-02T14:29:56.000Z",
"path": "/api/v1/invoices"
}Note that message is an array for validation failures and a string everywhere
else. Handle both.
Unknown fields are rejected
We do not ignore fields we do not recognise — a request containing one is a 400. This
is deliberate: a typo in a field name would otherwise look like a success while the value
you sent was silently dropped. It does mean you cannot send extra metadata of your own on
these endpoints.
Two distinctions worth keeping straight
401 versus 403. A 401 means we do not know who you are — check the key. A 403
means we do, and the answer is no — check scopes, or whether you are reaching another
business's data. Retrying a 403 with the same key will never succeed.
A 404 may mean "not in this environment". Staging sometimes runs ahead of
production, so an endpoint that works on staging can be genuinely absent in production
until the next release.