Skip to main content
Failures return a machine-readable code, a human message, an actionable hint, and a docs_url linking to the matching anchor on this page. Some errors add a param naming the offending field and a typed details map.
Switch on code. It is stable across versions. Do not parse message; it is for humans and may change. Where a code has no explicit status of its own, it answers 422, so treat 422 as the general “understood but cannot be applied” rather than as one specific fault.
Kordio Control returns a different envelope and a different set of codes. See Kordio Control: errors.

General

invalid_request

422 - The payload is malformed or missing required fields. When a specific field is at fault, param and details.fields identify it.

unauthorized

401 - No valid access token was presented. Include a Bearer token from POST /oauth/token.

forbidden

403 - The token is valid but not permitted to perform this operation.

insufficient_scope

403 - The token lacks the scope this endpoint requires. Scopes do not imply each other: ledger:write does not grant ledger:read. Re-request the token with both. See Scopes.

not_found

404 - The resource does not exist. Verify the id and that it belongs to your tenant and ledger.

rate_limited

429 - Back off per the Retry-After header and retry.

internal_error

500 - Unexpected. Retry; if it persists, contact support.

Write semantics

missing_idempotency_key

422 - A write was sent without the required Idempotency-Key header. Supply a key unique per logical request. See Idempotency.

unbalanced

422 - The transaction’s debits do not equal its credits in some currency. See Double-entry.

currency_mismatch

422 - A posting’s currency does not match the account it targets. Every posting must use its account’s currency.

unknown_account

422 - A posting references an account that does not exist. Create it before posting against it.

already_exists

409 - A resource with the same identifier or idempotency key already exists. Pick a different id, or patch the existing resource.

already_reversed

409 - The transaction has already been reversed. Fetch it and inspect reversed_by.

immutable_field

409 - You tried to change a field that cannot change after creation, such as a posting’s economic columns or an account’s currency.

insufficient_funds

422 - The source account would exceed its overdraft policy. The write was not applied.

account_closed

409 - The posting targets a closed account. Reopen nothing: post to a different account, or correct the entry that closed it.

account_balance_nonzero

409 - You tried to close an account whose posted or pending balance is not zero. Move the remaining value out first.

period_closed

409 - The value_date falls in a closed period. Book into the current open period, or reopen the period.

period_close_imbalanced

422 - The trial balance at period_end does not net to zero in some currency, so the period was not closed. details.residual_by_currency names the gap. Fix it, or close with force: true, which records who forced it.

precondition_failed

409 - An If-Match or If-Unmodified-Since precondition was not satisfied.

duplicate_external_ref

409 - An external_ref with this (rail, kind, value) is already attached to another transaction.

partial_refund_exceeds_original

422 - The refund amount plus prior partial refunds in this currency exceeds the original gross. See details.remaining_by_currency.

refund_currency_required

422 - The original transaction is multi-currency, so you must pass currency to disambiguate which leg you are refunding. See Multi-currency.

account_template_unknown

422 - The referenced account template does not exist. Create it first via POST /v1/account_templates, or omit template to use raw account fields.

invalid_state

409 - The resource is not in a state that permits this operation.

run_in_progress

409 - A reconciliation run for this source is already queued or running. One at a time per source. Wait for reconciliation.run_completed.

Credentials and lifecycle

rotation_in_progress

409 - The previous secret is still inside its 24-hour overlap window. Wait, or pass ?force=true to destroy it now.

webhook_endpoint_disabled

409 - The endpoint is disabled. Re-enable it via PATCH /v1/webhook_endpoints/{id} before sending.

fresh_authentication_required

401 - This destructive operation requires a token issued within the last five minutes. Mint a fresh one and retry.

tenant_suspended

403 - Your tenant is suspended. Contact support.

plan_required

402 - Your plan does not include this operation. Check Billing in the console.

OAuth

These follow RFC 6749 section 5.2 at the token endpoint.

invalid_client

401 - The client_id or client_secret is wrong, or the client is disabled.

invalid_grant

422 - The grant_type or its parameters are invalid.

invalid_scope

422 - The requested scope is not granted to this client.

unsupported_grant_type

422 - Only client_credentials is supported today.

Next steps

Ledger concepts

The rules these codes enforce.

API reference

Which codes each endpoint can return.