Swaps
Errors and limits
HTTP errors
Every error is JSON:
{ "error": "slippageBps must be 0..5000", "requestId": "3f1c9b9e-…" }| Status | Typical error | Meaning | What to do |
|---|---|---|---|
400 | invalid in / invalid recipient / amount must be a positive integer in base units / in and out must differ / slippageBps must be 0..5000 / minOut is required… | Bad input | Fix the request. Not retryable |
401 | invalid API key | An Authorization header with an unknown key | Fix or remove the key |
404 | no route | No path of ≤3 swaps between the tokens, or every candidate quoted 0 | Try another pair or a smaller amount |
404 | unknown token (not in any indexed pool) | /tokens/{address} for a token with no pool | — |
422 | honeypot: this token can be bought but not sold | The output token failed the probe | Don't trade it |
429 | Rate limit exceeded, retry in 1 minute | Too many requests | Wait retry-after seconds; get a partner key |
503 | indexer still backfilling | The instance just started and hasn't loaded all pools yet | Retry in a few seconds; poll /v1/health until ready |
503 | EXECUTOR_ADDRESS not configured / ORDERBOOK_ADDRESS / EXECUTOR_ADDRESS not configured | The operator hasn't configured that contract | — |
500 | internal error | Unexpected failure (usually the RPC) | Retry once; report the requestId |
Internal error details are never returned (they can contain the RPC URL or keys); they're logged server-side under the request id.
A 200 that you should not send
A 200 quote can still carry a transaction that would fail. Always check:
| Field | Bad value | Meaning |
|---|---|---|
simulation.ok | false | The exact tx reverts from sender right now; simulation.error says why |
tx.warning | present | Same thing, on the tx itself |
approval | not null | Approve first, then re-quote |
warnings | non-empty | Impersonator, taxes, launchpad… Show them to the user |
On-chain reverts
If the transaction was sent anyway, or the market moved between quote and inclusion:
| Contract error | Cause |
|---|---|
Expired() | Mined after deadline (quote + 5 min) |
InsufficientOutput(amountOut, minOut) | Price moved beyond the slippage tolerance |
PartialFill() | A pool hit its price limit and couldn't take the whole input |
InvalidRoute() | Malformed splits (legs don't add up to amountIn, wrong token chain, zero recipient) |
InvalidNativeConfig() | wrappedNative isn't allow-listed |
IsPaused() | The operator paused swaps (emergency stop) |
TransferFailed() | A token transfer or native send failed (blocked token, recipient can't receive HYPE) |
Unauthorized() | A callback came from a contract that isn't the active pool (only seen in attacks) |
OrderBook: InvalidOrder() (bad parameters, zero minOutPerSlice), NotFillable() (not due, expired or empty), Unauthorized() (non-keeper fill, non-owner cancel before expiry).
Limits
| Limit | Value |
|---|---|
| Public rate limit | RATE_LIMIT_PER_MIN per IP (default 120/min) |
| Partner rate limit | Per key (default 10× public) |
| Request timeout | 20 s server-side. Use a 10–20 s client timeout |
| Swaps per route | 3 (plus one WHYPE rewrap) |
| Split legs | 3, pool-disjoint |
| Split granularity | 5% |
slippageBps | 0–5000 |
/price ids | 100 per request |
/tokens limit | 500 |
/history limit | 200 |
| WebSocket subscriptions | 100 ids per socket |
| Order slices | 1–1000, and at most one slice per base unit of input |
| Quote deadline | 300 s |
Retries
- Retry
429(afterretry-after),503,500, and network errors: once or twice, with backoff. - Don't retry
400,401,404,422unchanged. - Re-quote rather than re-send when a transaction reverts with
ExpiredorInsufficientOutput.
Next: Limit orders and DCA