Skip to main content
Every error response has a non-2xx status code and a consistent body:
id mirrors the HTTP status, name is a stable machine-readable code, and detail is a human-readable explanation (its wording may change — branch on name, not detail).

Error codes

StatusnameWhen
400bad_requestInvalid JSON, missing/invalid fields, malformed amounts or dates, invalid cursor
401unauthorizedMissing, invalid, or revoked API key
403forbiddenRead-only key on a write endpoint, no access to the workspace, or workspace archived
404not_foundUnknown endpoint, or the workspace/account/transaction/merchant/category doesn’t exist
409conflictDuplicate name (e.g. merchant or category group already exists)
429rate_limit_exceededMore than 200 requests in an hour for this key
500internal_errorSomething went wrong on our side — retry with backoff, and contact support if it persists

Rate limiting

Each API key may make 200 requests per hour. When you exceed it, the response is 429 with a Retry-After header containing the number of seconds until the window resets:
Batch endpoints help you stay under the limit — for example, POST /transactions accepts up to 100 transactions in one request.

Validation errors reference fields by path

Field errors name the offending field, including array indices, so you can pinpoint the bad row in a batch: