Errors
Every refusal is a JSON body with a single message, and a status code that says
what kind of thing went wrong.
{ "message": "This credential may not call from this address." }
401 — the caller is not who it says
| Message | What it means |
|---|---|
The client id and secret do not match. | The exchange was given a client id or secret that does not exist |
This credential is revoked or has expired. | Revoked on the screen, or past its expiry date |
The refresh token is no longer valid. | Refreshed twice with one token, or it has expired |
The account that owns this credential no longer exists. | The creator’s account was removed |
403 — the caller is known, but not allowed
| Message | What it means |
|---|---|
This token was not issued by an API credential. | The bearer token predates the credential exchange, or is not from this API |
This credential is revoked or has expired. | Same credential, seen on a normal call rather than the exchange |
This credential may not call from this address. | The call’s address is outside the credential’s allowlist |
This credential was not issued for organisation {id}. | The organisation on the
route is not one of the companies ticked on the credential — a write. A read answers
404 instead, so it never confirms that another company exists |
This credential may not write {kind}. | The credential holds no
{kind}.write scope |
This credential does not hold the {scope} scope. | A read whose credential holds
no {resource}.read scope |
This account may no longer administer data for this organisation. | The account behind the credential lost its data-admin right on that organisation |
This account may no longer report on this organisation. | A read, where the account behind the credential lost its reporting right on that organisation |
This token may not write. | The token was issued without the write ability |
This token may not read. | The token was issued without the read ability |
404 — the path or the record does not exist
A read never confirms that a company it may not read exists: a company that is not one of the credential's
answers the same 404 as one that does not exist at all.
{ "message": "No such organisation.", "code": "not_found" }
The schema endpoint answers a kind it does not carry by name, and lists the kinds it does carry:
{ "message": "No such kind.",
"kinds": ["accounts", "trial_balance", "invoices", "bills", "transactions", "operation_data"] }
422 — the request was refused on its contents
The write endpoints refuse an invalid body in the same shape as the schema's own validation:
{ "message": "The request was refused.",
"errors": [{ "index": 3, "field": "records.3.amount_base", "code": "invalid_type", "detail": "…" }] }
A read refuses a parameter in the same envelope, with the field that was wrong and no record
index, because a read has no records:
{ "message": "The request was refused.",
"errors": [{ "field": "number_of_months", "code": "invalid_value",
"detail": "0 is not a number of months. Ask for 1 to 120." }] }
A read uses the codes the write side publishes: invalid_value for a value outside what the
endpoint takes, required_field_missing for one it needs - section on a detail read -
and unknown_field for a parameter the resource does not take, which is refused rather than
ignored so no caller believes a filter applied.
A body that passed its checks and then failed while writing answers with the code that failed, and stays readable at its own URL:
{ "message": "The request failed.",
"failure": { "code": "journal_does_not_balance", "errors": [ … ] } }
429 — too many requests
Token requests are limited to 10 a minute per caller. Data requests are limited per credential, at the group's own requests-per-minute figure — see Limits.