Rate limits
Every /v1 endpoint belongs to a limit tier. When the limit of a tier is full, we reject the request with 429 rate_limited and apply nothing. The tiers are independent of each other: heavy read traffic cannot use up your balance-sync budget.
Tiers and limits
We regenerate the table from the values in our capacity plan at every build. The limits are per minute.
| Tier | Endpoints | Per end user | Per tenant |
|---|---|---|---|
balance_sync | POST /v1/balance-syncPOST /v1/balance-sync/batch | None | 450/min |
user_sync | PUT /v1/users/{external_user_id} | None | 3,000/min |
positions | POST /v1/positionsPOST /v1/positions/{id}/closePOST /v1/ordersDELETE /v1/orders/{id} | 10/min | 4,500/min |
default | every other /v1 route | None | 600/min |
feed_read | GET /v1/marketsGET /v1/markets/{slug}GET /v1/markets/{slug}/snapshotGET /v1/markets/{slug}/history | 60/min | 600/min |
widget_session | POST /v1/widget/sessionsPOST /v1/widget/sessions/refreshGET /v1/widget/configPOST /v1/widget/error-reportsGET/PUT/DELETE /v1/widget/profileGET /v1/widget/leaderboard | 10/min | 13,500/min |
users_me | GET /v1/users/me | 60/min | 4,500/min |
saved_markets | GET /v1/widget/saved-marketsPUT /v1/widget/saved-markets/{market_slug}DELETE /v1/widget/saved-markets/{market_slug} | 20/min | 5,400/min |
Tenant limit and end-user limit
Every tier has a tenant limit. It counts the total traffic of your tenant in that tier. Its purpose is to stop a sudden load from one operator from slowing another operator.
Some tiers also have a limit for each end user. It counts per external_user_id. It stops excessive traffic from one end user. In every tier except feed_read, it does not change the tenant limit: whatever your number of users, the total traffic of your tenant stays within the tenant limit.
The end-user limit applies only to requests that arrive with a widget session token. Requests that you send from your own server with the API key have only the tenant limit. For example, your server requests in the positions and feed_read tiers, and your session-opening request POST /v1/widget/sessions, do not meet the end-user limit.
The feed_read tier counts the two credentials apart. Reads that you send with your API key count against the tenant limit. Reads that arrive with a widget session token count against the end-user limit only, and never against the tenant limit. Many end users of your tenant can read the feed at the same time, each within the end-user limit, and your own server keeps its whole tenant limit.
When you receive a 429
The Retry-After header of the response gives the wait time in seconds. Wait that long, then send the request again. If you retry at once and repeatedly, the limit stays active for longer.
Send write requests again with the same Idempotency-Key and the same body. This retry is safe because a rejected request applies nothing: the request is applied once or not at all. Read requests have no side effect, so you can retry them directly.
Many balance syncs
If you receive 429 in the balance_sync tier, do not send the syncs one by one. Send them in a batch with POST /v1/balance-sync/batch. One batch request counts as a single request against the tier limit. The 429 response in this tier also points you to the batch endpoint.
Syncing users
PUT /v1/users/{external_user_id} has its own tier, user_sync. Syncing users does not use your balance_sync limit, and balance syncs do not use your user_sync limit.
Raising a limit
The values in the table are the default for every tenant. If your traffic regularly exceeds a tenant limit, you can ask for a raise. Open the request as a support ticket from the tenant portal or with POST /v1/support-tickets. In the ticket, write the tier and the traffic that you expect.
A raise applies only to the tenant limit of the balance_sync, positions and default tiers. The end-user limits, widget_session, users_me, saved_markets and feed_read are not raised. A raised limit is part of the agreement with you, and it takes effect with our next deployment.