Errors

HTTP status codes, error codes, and recommended handling.

Error response shape

Every error response shares a common JSON shape:

1{
2 "code": "rate_limit_exceeded",
3 "message": "Too many requests.",
4 "docs_url": "https://docs.agora.finance/api/errors"
5}
FieldTypeDescription
codestringMachine-readable error code. Stable — safe to match on in code.
messagestringHuman-readable explanation. May change without notice — do not match on it.
docs_urlstringLink back to this page for deeper context.
contextobject | omittedPer-error structured details. Present only when the error code carries them — parameter_invalid, unauthorized, and route_already_exists today. See Error context.

Every response — success or error — also includes a Request-Id header. Log it; Agora support uses it to trace requests end-to-end.

Error codes

HTTPcodeWhen it happensRecommended handling
400parameter_invalidOne or more request parameters fail validation. The response includes a context.issues array with per-field details.Inspect context.issues for the offending field; correct the request and retry.
400chain_unsupportedThe request references a chain Agora does not support.Use a supported chain.
400currency_unsupportedThe request references a currency Agora does not support for this operation.Use a supported currency — see the supported topologies on POST /v0/routes.
400direction_unsupportedThe from/to pair does not resolve to a supported route direction.Check the supported topologies on POST /v0/routes and adjust from/to.
401unauthorizedAuthentication is missing or failed. The specific cause is in context.reason — see Authentication failures.Resolve per the reason; typically exchange or refresh your session JWT. See the Authentication guide.
403forbiddenAuthentication succeeded but the credential lacks permission for this resource.Confirm the key is provisioned for the requested operation; otherwise contact your Agora account manager.
404not_foundThe requested resource does not exist (generic fallback).Verify the URL and method. The current surface is documented under Endpoints.
404account_not_foundThe referenced account does not exist for your organization.Verify the account id against GET /v0/accounts.
404route_not_foundThe referenced route does not exist for your organization.Verify the route id against GET /v0/routes.
409route_already_existsA route with these parameters already exists. The response includes context.routeId with the existing route’s id.Use the existing route — route ids are deterministic; fetch it via GET /v0/routes/{routeId} using context.routeId.
429rate_limit_exceededThe per-IP rate limit at the Cloudflare edge was exceeded. The response includes a Retry-After header (seconds).Wait the Retry-After duration, then retry. Use exponential backoff for repeat triggers.
500internal_errorAn unexpected server-side failure. The response intentionally omits internal details.Retry with exponential backoff. If it persists, capture the Request-Id and contact support.
503route_creation_unavailableRoute creation is temporarily unavailable.Retry after a short delay with exponential backoff. If it persists, capture the Request-Id and contact support.
503service_unavailableThe service is temporarily unavailable.Retry after a short delay with exponential backoff.

Authentication failures (401)

A 401 unauthorized response carries a context.reason naming the specific cause, so clients can branch without parsing message:

1{
2 "code": "unauthorized",
3 "message": "Authentication is required.",
4 "docs_url": "https://docs.agora.finance/api/errors",
5 "context": { "reason": "token_expired" }
6}
reasonWhen it happensRecommended handling
missing_headerNo Authorization: Bearer header on the request.Attach the session JWT and retry.
invalid_tokenThe bearer token is malformed or failed validation (signature, audience, or issuer).Re-exchange your API key for a fresh JWT.
token_expiredThe session JWT is past its 15-minute lifetime.Exchange your API key again and retry.
token_revokedThe API key behind this session has been revoked.Request a new API key from the Agora team.
unknown_tenantThe token does not resolve to a known organization.Re-exchange; if it persists, contact support.
missing_claimThe token verified but is missing a required claim.Should not occur with tokens from /v0/auth/token; treat as a bug and capture the Request-Id.

See the Authentication guide for the full exchange and refresh flow.

Error context

Three codes attach a context object; all others omit it.

parameter_invalid returns a context.issues array describing each validation failure:

1{
2 "code": "parameter_invalid",
3 "message": "One or more request parameters are invalid.",
4 "docs_url": "https://docs.agora.finance/api/errors",
5 "context": {
6 "issues": [
7 { "field": "amount", "message": "Must be a positive decimal string." },
8 { "field": "destination.chain", "message": "Unsupported chain. Supported: ethereum, solana, monad." }
9 ]
10 }
11}

Illustrative example. The fields shown above are illustrative. The context.issues shape is stable across every endpoint that emits parameter_invalid.

unauthorized returns a context.reason — see Authentication failures above.

route_already_exists returns a context.routeId — the id of the pre-existing route. Route ids are deterministic, so you can use it directly (e.g. fetch the route via GET /v0/routes/{routeId}).

Handling errors programmatically

  • Match on code, never on message. Messages are human-readable and may change without notice. For 401, branch on context.reason.
  • Use the HTTP status as a secondary filter. Status plus code together fully disambiguate every error.
  • Persist the Request-Id header. It is the single best lever for diagnosing issues with Agora support.
  • Retry-with-backoff for 429, 500, and 503. Honor Retry-After when present. The 503 codes (route_creation_unavailable, service_unavailable) are transient and safe to retry.