Rate limits
Token buckets per policy, keyed by caller. The real numbers.
Every route takes one token from a bucket before it does anything else. A bucket refills continuously at its sustained rate and holds at most its burst, so a caller may arrive in a clump and then settles to the rate.
A token bucket rather than a fixed window, deliberately: a fixed window lets a caller send a whole window's worth at the boundary and the same again a moment later, which is exactly the burst it is meant to prevent.
The policies
Read from the live policy object rather than transcribed. Burst is the bucket's capacity; where a policy sets none it equals the sustained rate.
| Policy | Per minute | Burst |
|---|---|---|
quote | 30 | 10 |
relay | 600 | 120 |
status | 300 | 60 |
list | 600 | 120 |
write | 10 | 5 |
trade | 60 | 20 |
exit | 120 | 30 |
Which policy a route uses
| Policy | Routes |
|---|---|
| list | Most reads: markets, market-rules, candles, funding, config, tokens, deposit-chains, insurance-fund, liquidations, leaderboard, whales, points, catalogue, referral verify, swap chains, swap tokens, earn meta, earn vaults, and every catalogued operation on the list policy. |
| status | The two that a live terminal polls hardest: orderbook and trades, plus the swap status route and the markets.trades operation. |
| quote | The swap quote route, because each call is a priced upstream request. |
| relay | POST /api/prep/relay, counted twice: once against your address and once against the account id in the envelope. |
| write | Account creation and referral claims: register, registration-nonce, trading-key and referral/code. |
The relay policy is generous on purpose. It is not there to protect the venue from you, who are spending your own quota under your own key; it is there so a runaway client cannot turn this server into an amplifier. An open terminal legitimately polls positions, orders and balances at once.
Being limited
Going over returns 429 with code rate_limited and a retry-after header of 10 seconds. It is marked retryable, so back off and try once rather than looping.
HTTP/1.1 429
retry-after: 10
{ "code": "rate_limited", "error": "Too many requests. Wait a moment and try again." }How a caller is identified
By the first address in x-forwarded-for, falling back to x-real-ip and then cf-connecting-ip. Callers behind the same address share a bucket, which is why the relay adds a second bucket keyed on the account id.
Caching is cheaper than a limit
Most reads carry a cache-control header, and honouring it is the simplest way never to see a 429. Market rules are good for an hour, the catalogue for five minutes, markets for five seconds, and the order book for none at all.