Skip to navigation

Errors

HTTP status codes, error codes, and recommended handling.
← Switch to the Production API

This is the sandbox. It runs on testnets only. Never send real money or real tokens to an address or bank account the sandbox returns.

The sandbox is subject to the Beta Features section of our Terms of Use.

Sandbox errors use the same codes and shapes as production. A few behave differently:

  • Dashboard fixes. The sandbox has no dashboard yet. Where a fix below says to use the dashboard, contact Agora instead.
  • direction_unsupported is returned for any route pair outside the four the sandbox supports.
  • route_creation_unavailable means the sandbox ran out of deposit addresses. It refills, so retry shortly.

Error response shape

Every error response shares a common JSON shape:

{
"code": "rate_limit_exceeded",
"message": "Too many requests.",
"docs_url": "https://docs.agora.finance/api/errors"
}
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.
400entitlement_not_requestableThe requested entitlement can’t be requested for that account or network (unsupported, or already present). The response includes a context.issues array.Inspect context.issues; request a supported entitlement on a supported network.
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.Check the roles on the key in the dashboard; otherwise contact your Agora account manager.
403account_not_eligibleYour organization, or the destination account for the requested chain, isn’t eligible for this operation.Contact your Agora account manager to enable it.
403account_not_provisionedYour organization isn’t provisioned for the product this endpoint belongs to.Contact your Agora account manager to have the product enabled.
403account_verification_pendingYour organization is provisioned for the product, but verification for it hasn’t completed.Wait for verification to complete, then retry; the check runs per request. Contact your Agora account manager if it stays pending.
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.
404transaction_not_foundThe referenced transaction does not exist for your organization.Verify the transaction id against GET /v0/transactions.
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.
409account_already_existsAn account with these details is already registered for your organization (including registering a wallet on a network it already holds).Fetch it via GET /v0/accounts instead of re-creating it.
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:

{
"code": "unauthorized",
"message": "Authentication is required.",
"docs_url": "https://docs.agora.finance/api/errors",
"context": { "reason": "token_expired" }
}
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_pausedThe API key behind this session is paused.Resume the key from the dashboard, then retry.
token_revokedThe API key behind this session has been revoked.Create a new API key from the dashboard.
key_not_provisionedThe key wasn’t created through the dashboard and is no longer usable.Create a new API key from the dashboard.
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:

{
"code": "parameter_invalid",
"message": "One or more request parameters are invalid.",
"docs_url": "https://docs.agora.finance/api/errors",
"context": {
"issues": [
{ "field": "amount", "message": "Must be a positive decimal string." },
{ "field": "destination.chain", "message": "Unsupported chain. Supported: avalanche-fuji, ethereum-sepolia." }
]
}
}

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.