Errors
The error format, HTTP statuses, and every error code.
Format
Every error response has a JSON body with a stable, machine-readable code and a human-readable
message. Some add details.
{
"code": "splits_do_not_sum",
"message": "The splits add up to $50.00, but the amount is $54.20.",
"details": { }
}- Branch on
code, never onmessage. Codes are stable within/v1; messages may change. messageis safe to show to a user.detailsis an object whose contents depend on the code (for exampledetails.required_scopeforinsufficient_scope). Ignore keys you don't know.- New codes may be added in
/v1. Treat an unknown code by its HTTP status.
Statuses
| Status | Meaning |
|---|---|
400 | The request didn't parse: malformed JSON, a wrong type, or a bad parameter (invalid). |
401 | No valid credentials: missing, revoked, or expired token. |
403 | Authenticated, but not allowed: missing scope, not a member, not the owner, and so on. |
404 | No such thing (or no budget for that month yet). |
409 | Conflicts with what exists: a name that's taken, a month that exists, a reused transaction ID. |
410 | A link that was valid but isn't any more (an expired or used invite or email link). |
422 | Well-formed, but breaks a budgeting rule (the splits don't add up, the item isn't in that month, …). |
429 | Too many requests. See Rate limits. |
500 | Something went wrong on our side (internal). It's reported to us automatically; retry later. |
Codes
Authentication and access
| Code | Status | Meaning |
|---|---|---|
unauthenticated | 401 | No credentials, or the token or session is revoked or expired. |
insufficient_scope | 403 | The token lacks the scope this operation needs; details.required_scope names it. See scopes. |
session_required | 403 | Only a signed-in session can do this (managing tokens, changing your password). |
not_invited | 403 | Signing in: the account isn't on the invite list and has no pending invite. |
not_a_member | 403 | You aren't a current member of that household. See Households. |
not_owner | 403 | Only the household's owner can do this. |
rate_limited | 429 | Too many requests; wait Retry-After seconds. |
Budgets, groups, and items
| Code | Status | Meaning |
|---|---|---|
not_found | 404 | No such group, item, transaction, household, or invite (or it isn't in this household). |
month_not_created | 404 / 422 | The month has no budget yet: 404 when reading it, 422 when writing to it. Create it with POST /months/{month}. |
month_exists | 409 | The month already has a budget. |
no_previous_month | 409 | Resetting with "replace" needs an earlier budget to copy, and there isn't one. |
name_taken | 409 | A group or item with that name already exists (names are unique within a budget). |
income_group_protected | 422 | The Income group can't be deleted. |
kind_mismatch | 422 | The item's kind doesn't allow this: income items can't be funds, favorites, or harvested, can't leave Income; funds can't be harvested; an expense can't be split to an income item. |
already_fund | 422 | The item is already a fund. |
not_fund | 422 | The operation only applies to funds. |
nothing_to_harvest | 422 | The item has nothing left over to move back to Left to Budget. |
invalid | 400 / 422 | Generic validation failure; message says what's wrong. |
Transactions
| Code | Status | Meaning |
|---|---|---|
id_conflict | 409 | That transaction ID was already used with a different body. See Idempotency. |
amount_not_positive | 422 | Amounts must be greater than zero (the type gives the direction). |
split_not_positive | 422 | Every split's amount must be greater than zero. |
splits_do_not_sum | 422 | The splits must add up to the transaction's amount. |
duplicate_split_item | 422 | Two splits point at the same item. |
item_not_in_month | 422 | A split's item doesn't exist in the transaction's budget month. |
Households and invites
| Code | Status | Meaning |
|---|---|---|
already_member | 409 | That person is already in the household. |
invite_email_mismatch | 403 | The invite was sent to a different email than the one you're signed in with. |
invite_unavailable | 410 | The invite expired, or was revoked, declined, or already accepted. |
last_household | 422 | You can't leave, delete, or archive your only (non-archived) household. |
personal_household | 422 | Your personal household can't be deleted, and its owner can't leave it. |
owner_must_transfer | 422 | Transfer ownership before leaving a household others still belong to. |
default_household | 422 | Your default household can't be archived; pick another default first. |
household_archived | 422 | An archived household can't be your default. |
choose_default | 422 | Leaving your default household: say which household becomes the new default. |
Email + password accounts
These apply only where email + password sign-in is turned on.
| Code | Status | Meaning |
|---|---|---|
bad_credentials | 401 | Email or password is incorrect. |
email_unverified | 403 | Verify the email address first. |
invalid_link | 410 | The email link expired or was already used. |
Server
| Code | Status | Meaning |
|---|---|---|
internal | 500 | Unexpected error. Retry later; if it keeps happening, let us know. |