API

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.

The shape
{
  "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.

CodeStatusRetryMessage
invalid_request400FinalThat request was missing something or malformed.
invalid_address400FinalThat wallet address is not valid.
invalid_amount400FinalEnter an amount greater than zero.
invalid_chain400FinalThat network is not one this app supports.
invalid_token400FinalThat token is not available on the selected network.
unsupported_pair400FinalThis pair cannot be swapped. Pick a different token.
identical_tokens400FinalChoose two different tokens.
unauthorized401FinalSign in with your wallet to continue.
forbidden403FinalThis account cannot perform that action.
invalid_signature401FinalThat signature could not be verified. Try signing again.
expired_signature401FinalThat signature has expired. Sign again to continue.
rate_limited429RetryableToo many requests. Wait a moment and try again.
settle_first400FinalSettle your profit and loss first. The venue will not process a withdrawal while there is an unsettled balance against this account.
insufficient_margin400FinalThat would leave too little margin behind. Close or reduce a position, or withdraw less.
risk_too_high400FinalThat order is too large for the collateral behind it, or the leverage is too low for its size.
key_rejected401FinalThis browser is no longer authorised to act on your account. Re-enable trading and try again.
referral_code_taken409FinalThat code is already taken. Try another.
referral_code_bound409FinalSomebody has already joined with that code, so it cannot be changed.
referral_code_held409FinalThis account already has a referral link.
referral_code_unknown404FinalThat referral code does not exist.
no_route404FinalNo route is available for this swap right now.
insufficient_liquidity409RetryableThere is not enough liquidity for an amount this size.
amount_too_small400FinalThat amount is below the minimum for this route.
amount_too_large400FinalThat amount is above the maximum for this route.
quote_expired410FinalThis quote has expired. Refresh for current pricing.
slippage_exceeded409RetryableThe price moved past your slippage limit. Try again or raise the limit.
insufficient_balance400FinalYour balance is too low for this amount.
insufficient_allowance400FinalThis token needs approval before it can be spent.
insufficient_gas400FinalYou need more of the network's native token to cover gas.
simulation_failed409FinalThis transaction would fail on chain, so it was not offered.
chain_unreachable503RetryableThat network is not responding. Try again shortly.
not_found404FinalThat was not found.
timeout504RetryableThat took too long to answer. Try again.
unavailable503RetryableThis service is briefly unavailable. Try again shortly.
internal_error500RetryableSomething 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.