Reference

Errors

Every error response carries a stable, machine-readable error type and a human-readable message. Branch on error, never on message — the type is a versioned contract, the message is free text and may change at any time.

Error shape

There are two error shapes, depending on the route. Read, list, and delete routes return a compact body keyed by ok. Create routes (POST /v1/orders, POST /v1/deposits, POST /v1/withdrawals, …) return a richer body keyed by success. Both carry the same error type and message, so branching on error works everywhere.

error response — read, list & delete routes
{
  "ok": false,
  "message": "Order not found",
  "error": "ExistenceError"
}
error response — create routes
{
  "success": false,
  "error": "ExistenceError",
  "message": "Quote not found",
  "errorId": "ExistenceError-1751712000000",
  "errorName": "ExistenceError"
}

errorId and errorName appear only on create-route errors. errorId is the errorName plus a timestamp (ExistenceError-1751712000000) — treat both as context for logging and support, and always drive control flow from error.

Error types

The complete set of error values, with the exact HTTP status each type returns.

TypeHTTPMeaningWhat to do
ValidationError 400 The request body or parameters failed validation. Fix the request — check field names, types, required fields, and formats, then retry.
ExistenceError 404 A referenced resource does not exist. Check the id you sent — the quote, order, or deposit may be wrong or expired.
StateError 409 The resource is not in a state that allows this operation. Re-read the resource state; wait for or move it to a valid state before retrying.
DuplicityError 409 The operation would create a duplicate resource. Dedupe — reuse the existing resource rather than resending.
AuthorizationError 401 Missing or invalid credentials, or insufficient permission. Authentication and authorization failures both return 401. Fetch a fresh token and replay the request once; if it still fails, check the workspace's permissions.
AllowanceError 403 The action exceeds a configured limit or allowance. This is the only type that returns 403. Check the workspace's limits and permissions; request a higher allowance if you need one.
FundsError 402 Insufficient balance to complete the operation. Check the workspace balance and top up before retrying.
ExternalServiceError 503 A downstream dependency was temporarily unavailable. Retry with exponential backoff. On writes, reconcile first — see Retrying a write.
OperationError 503 An unexpected error occurred while processing the request. Also returned when the write rate limit is exceeded. Retry with backoff; if it persists, contact support with the errorId.

Rate limits return 503, not 429. Exceeding the write rate limit returns HTTP 503 with OperationError — retry with backoff. A rate-limited request created nothing, so resending it is safe. See Rate limits for thresholds and headers.

Handling patterns

A small decision tree covers almost every case. Switch on error first, then fall back to the HTTP status class.

4xx is your request. A 400 means malformed input and a 404 means a bad id — fix the request before retrying, as an identical retry will fail the same way.

401 → refresh the token. Bearer tokens are short-lived; on a 401 AuthorizationError, fetch a new token and replay the request once. Authentication and permission failures both surface as 401 — if a fresh token still fails, check the workspace's permissions.

409 → state or duplicate. A StateError means the resource moved on — re-read it. A DuplicityError means the resource already exists — reuse it rather than creating another.

5xx and ExternalServiceError are transient. Retry reads freely with exponential backoff. Writes are not de-duplicated — if a create timed out, reconcile before resending or you may create a second payment. See Retrying a write.

← Prev
EUR → USDC payout