Errors
A closed set. Every code, its status and whether it can be retried.
Nothing here invents an error at runtime. Anything unrecognised collapses to internal_error, which means the set your client has to handle is finite, stable and small enough to switch on.
{
"code": "insufficient_balance",
"error": "Your balance is too low for this amount.",
"meta": { "minimum": 10 }
}code is the machine-readable half and is the only thing to branch on. error is a sentence that is safe to show a user as written. meta is present only when there is a structured, already-safe extra, such as a minimum amount.
Never match on the words. The sentence is chosen for a reader and can be reworded; the code is a contract. A sentence written by an upstream provider never reaches you at all, because forwarding one would name infrastructure this product does not name.
Retrying
- retryable true means the same call, unchanged, could succeed later. Back off and try once more.
- retryable false means it will fail identically until something about the request changes.
- rate_limited also carries a retry-after header of 10 seconds.
- A write is the exception to all of this. Never blindly retry an order: read your positions first, because a retry after a partial fill doubles it.
The catalogue
Generated from the same object the server answers with, so it cannot list a code that does not exist or miss one that does. The same list is served as JSON under errors at GET /api/prep/catalogue.
| Code | Status | Retry | Message |
|---|---|---|---|
invalid_request | 400 | Final | That request was missing something or malformed. |
invalid_address | 400 | Final | That wallet address is not valid. |
invalid_amount | 400 | Final | Enter an amount greater than zero. |
invalid_chain | 400 | Final | That network is not one this app supports. |
invalid_token | 400 | Final | That token is not available on the selected network. |
unsupported_pair | 400 | Final | This pair cannot be swapped. Pick a different token. |
identical_tokens | 400 | Final | Choose two different tokens. |
unauthorized | 401 | Final | Sign in with your wallet to continue. |
forbidden | 403 | Final | This account cannot perform that action. |
invalid_signature | 401 | Final | That signature could not be verified. Try signing again. |
expired_signature | 401 | Final | That signature has expired. Sign again to continue. |
rate_limited | 429 | Retryable | Too many requests. Wait a moment and try again. |
settle_first | 400 | Final | Settle your profit and loss first. The venue will not process a withdrawal while there is an unsettled balance against this account. |
insufficient_margin | 400 | Final | That would leave too little margin behind. Close or reduce a position, or withdraw less. |
risk_too_high | 400 | Final | That order is too large for the collateral behind it, or the leverage is too low for its size. |
key_rejected | 401 | Final | This browser is no longer authorised to act on your account. Re-enable trading and try again. |
referral_code_taken | 409 | Final | That code is already taken. Try another. |
referral_code_bound | 409 | Final | Somebody has already joined with that code, so it cannot be changed. |
referral_code_held | 409 | Final | This account already has a referral link. |
referral_code_unknown | 404 | Final | That referral code does not exist. |
no_route | 404 | Final | No route is available for this swap right now. |
insufficient_liquidity | 409 | Retryable | There is not enough liquidity for an amount this size. |
amount_too_small | 400 | Final | That amount is below the minimum for this route. |
amount_too_large | 400 | Final | That amount is above the maximum for this route. |
quote_expired | 410 | Final | This quote has expired. Refresh for current pricing. |
slippage_exceeded | 409 | Retryable | The price moved past your slippage limit. Try again or raise the limit. |
insufficient_balance | 400 | Final | Your balance is too low for this amount. |
insufficient_allowance | 400 | Final | This token needs approval before it can be spent. |
insufficient_gas | 400 | Final | You need more of the network's native token to cover gas. |
simulation_failed | 409 | Final | This transaction would fail on chain, so it was not offered. |
chain_unreachable | 503 | Retryable | That network is not responding. Try again shortly. |
not_found | 404 | Final | That was not found. |
timeout | 504 | Retryable | That took too long to answer. Try again. |
unavailable | 503 | Retryable | This service is briefly unavailable. Try again shortly. |
internal_error | 500 | Retryable | Something went wrong on our side. |
Two routes answer their non-rate-limit failures as { "error": "..." } with no code: /api/swap/status and /api/relayer/voucher. Handle a missing code as internal_error rather than crashing on it.