Skip to content
Ledgerline Help

Error format and codes

Updated 24 September 20264 min read

On this page

Ledgerline uses conventional HTTP status codes to say whether a request worked, and a consistent JSON body to say why it did not. Branch your code on the type and code, never on the message, which can change.

The error object

Every error response has the same shape:

{
  "error": {
    "type": "invalid_request_error",
    "code": "entries_unbalanced",
    "message": "Debits (480000) and credits (450000) in USD must be equal.",
    "param": "entries",
    "request_id": "req_01JA9G3RWB",
    "doc_url": "https://docs.ledgerline.dev/errors/entries_unbalanced"
  }
}
Field Description
type The broad category. Stable and safe to switch on.
code A specific, stable machine-readable reason.
message A human-readable explanation. For logs and developers, not end users.
param The request field at fault, when one applies.
request_id The id of the request, also in the Ledgerline-Request-Id header. Include it in any report.
doc_url A link to the documentation for the code.

HTTP status codes

Status Meaning Typical type
200 OK
201 Created
202 Accepted for asynchronous processing
400 The request is malformed invalid_request_error
401 Authentication failed authentication_error
403 Authenticated, but not allowed permission_error, compliance_error
404 The resource does not exist not_found_error
409 Conflicts with current state conflict_error
422 Well-formed, but cannot be processed invalid_request_error
429 Rate limit exceeded rate_limit_error
500 Ledgerline had an internal error api_error
502, 503, 504 Temporary upstream or availability problem api_error

Ledgerline does not use 3xx responses for API calls and does not return 5xx for anything caused by your input.

Error types

Type Meaning
invalid_request_error The request or its parameters are wrong. Fix the request.
authentication_error The key is missing, invalid, revoked or expired.
permission_error The key is valid but lacks scope or is outside its IP allowlist.
not_found_error The id does not exist in this environment.
conflict_error The request conflicts with existing state or an in-flight request.
rate_limit_error You are sending requests too fast.
compliance_error A verification or screening rule blocked the action.
api_error Something went wrong on our side. Retry.

Error codes

Authentication and permissions

Code Status Meaning
api_key_invalid 401 The key is missing or malformed.
api_key_revoked 401 The key was revoked.
api_key_expired 401 The key passed its expires_at.
scope_missing 403 A restricted key lacks the required scope.
ip_not_allowed 403 The caller's IP is outside the key's allowlist.
permission_denied 403 The operation needs a secret key or the dashboard.

Ledger and transactions

Code Status Meaning
entries_unbalanced 422 Debits and credits are not equal in some currency.
insufficient_funds 422 The available balance is too low.
account_frozen 422 The account is frozen.
currency_mismatch 422 An entry's currency differs from its account's.
period_closed 422 effective_at is more than 90 days in the past.
resource_already_reversed 409 The transaction was already reversed.

Money movement and compliance

Code Status Meaning
counterparty_unverified 422 The bank account has not been verified.
limit_exceeded 422 A per-payout or daily limit would be exceeded.
rail_unavailable_for_recipient 422 The receiving bank does not support the rail.
kyb_required 403 Business verification is not approved.
sanctions_hit 403 Screening matched a restricted party.
fx_market_closed 422 Quotes are unavailable while FX markets are closed.
quote_expired 422 The FX quote is older than 30 seconds.

Requests and rates

Code Status Meaning
parameter_missing 400 A required field is absent.
parameter_invalid 400 A field has the wrong type or value.
resource_not_found 404 No such id. Check you are using the right environment.
idempotency_conflict 409 The first request with this key is still running.
idempotency_key_mismatch 422 The key was reused with different parameters.
rate_limit_exceeded 429 Over the limit. Honor Retry-After.
internal_error 500 An unexpected error on our side.
service_unavailable 503 Temporarily unavailable. Retry with backoff.

Handling errors in code

try {
  await ll.payouts.create(params);
} catch (error) {
  if (error instanceof LedgerlineError) {
    switch (error.code) {
      case "insufficient_funds":
        return notifyTreasury(error.requestId);
      case "counterparty_unverified":
        return startVerification(params.counterpartyBankAccountId);
      default:
        throw error;
    }
  }
  throw error;
}

Which errors to retry is covered in Retries and backoff. Practical fixes for the common ones are in Troubleshooting common errors.

Reporting a problem

When you open a support ticket, include the request_id. It lets us find the exact request and the logs around it, which are kept for 30 days.