Rate Limits
Rate limits protect the platform from abuse and ensure fair access for all users. Limits are enforced per-IP for unauthenticated requests and per-API-key for authenticated requests.
API Key Tiers
Each API key is assigned a rate limit tier that governs the overall request throughput:
| Tier | Limit | Description |
|---|---|---|
standard | 10 req/s | Default for new keys |
premium | 50 req/s | Premium integrations |
market_maker | 100 req/s | High-frequency market makers |
Administrators can also set per-key custom overrides via the rate_limit_override field. Custom overrides take precedence over the tier default. The override is a JSON object:
{ "requests": 200, "window_seconds": 1 }
Per-Endpoint Limits
Individual endpoints have their own rate limits. These per-endpoint limits apply to anonymous (per-IP) and session traffic. For HMAC API-key traffic the tier limit replaces the per-endpoint default on every endpoint - a market_maker key gets its 100 req/s ceiling on each endpoint it calls (per endpoint, per key; the tier is not an aggregate account budget).
Public Endpoints
| Method | Endpoint | Limit | Window |
|---|---|---|---|
| GET | /v1/markets | 100 req | 1 min |
| GET | /v1/markets/:id | 200 req | 1 min |
| All | All other unlisted endpoints | 30 req | 1 min |
Authentication Endpoints
| Method | Endpoint | Limit | Window |
|---|---|---|---|
| POST | /v1/auth/privy | 10 req | 1 min |
| POST | /v1/auth/callback | 10 req | 1 min |
| GET | /v1/auth/oauth/:provider | 10 req | 1 min |
| POST | /v1/auth/refresh | 5 req | 1 min |
| POST | /v1/auth/revoke | 10 req | 1 min |
| POST | /v1/auth/revoke-all | 5 req | 1 min |
| GET | /v1/wallets/link/nonce | 10 req | 1 min |
| POST | /v1/wallets/link | 10 req | 1 min |
Fiat Endpoints
| Method | Endpoint | Limit | Window |
|---|---|---|---|
| POST | /v1/user/fiat/offramp/sessions | 5 req | 1 min |
| POST | /v1/user/fiat/onramp/sessions | 10 req | 1 min |
| POST | /v1/user/fiat/onramp/sessions/:id/complete | 20 req | 1 min |
Trading Endpoints
| Method | Endpoint | Limit | Window |
|---|---|---|---|
| POST | /v1/orders | 10 req | 1 sec |
| DELETE | /v1/orders/:hash | 20 req | 1 sec |
| GET | /v1/orders/:hash | 20 req | 1 sec |
| POST | /v1/orders/cancel-replace | 10 req | 1 sec |
| PUT | /v1/orders/:hash/amend | 10 req | 1 sec |
Market makers: the 10/s in this table is the anonymous/session default. An API key's tier limit replaces it - a
market_makerkey gets 100/s on single-orderPOST /v1/orders(and 100/s on each other endpoint, per endpoint).POST /v1/orders/batch(up to 15 orders per call) still multiplies placement throughput per request and is the recommended way to quote.
Batch Trading Endpoints
| Method | Endpoint | Limit | Window |
|---|---|---|---|
| POST | /v1/orders/batch | 5 req | 1 sec |
| DELETE | /v1/orders/batch | 5 req | 1 sec |
| DELETE | /v1/orders/cancel-all | 2 req | 1 sec |
| DELETE | /v1/orders/cancel-market | 2 req | 1 sec |
| POST | /v1/orders/heartbeat | 1 req | 1 sec |
Deployment Endpoints
| Method | Endpoint | Limit | Window |
|---|---|---|---|
| POST | /v1/markets/:id/deploy | 20 req | 1 min |
Admin Endpoints
| Method | Endpoint | Limit | Window |
|---|---|---|---|
| POST | /admin/markets | 10 req | 1 min |
| POST | /admin/markets/:id/resolve | 5 req | 1 min |
Response Headers
Responses evaluated by the API rate limiter include its exact decision and configured policy:
| Header | Description |
|---|---|
X-RateLimit-Decision | allowed, quota_denied, or dependency_unavailable |
X-RateLimit-Limit | Maximum requests per configured window |
X-RateLimit-Window-Seconds | Configured window length in seconds |
X-RateLimit-Remaining | Authoritative requests remaining; omitted when the Redis authority is down |
X-RateLimit-Reset | Unix timestamp when the current window resets; omitted when authority is down |
Exceeded Limits
When you exhaust your rate limit, the API returns 429 Too Many Requests with
X-RateLimit-Decision: quota_denied:
{
"error": "Rate limit exceeded",
"code": "RATE_LIMITED"
}
Back off and retry after the X-RateLimit-Reset timestamp.
RATE_LIMIT_DEPENDENCY_UNAVAILABLE
If Redis cannot authoritatively read the counter, production fails closed with the same HTTP status but a distinct decision:
{
"error": "Rate limit authority is temporarily unavailable",
"code": "RATE_LIMIT_DEPENDENCY_UNAVAILABLE"
}
That response has X-RateLimit-Decision: dependency_unavailable and a short
Retry-After, but deliberately omits X-RateLimit-Remaining and
X-RateLimit-Reset. It is an infrastructure retry, not evidence that your
quota is exhausted and not a reason to upgrade a plan or key tier.
Best Practices
- Use batch endpoints to reduce request count (up to 15 orders per batch - see
/api/v1/batch-operations) - Cache market data locally and use WebSocket for real-time updates
- Monitor the decision - distinguish
quota_deniedfromdependency_unavailable; only the former proves an exhausted counter - Monitor headers - check
X-RateLimit-Remainingon authoritativeallowed/quota_deniedresponses to avoid hitting limits - Use cancel-all instead of individual cancels when unwinding positions
- Upgrade your tier - contact support if you need higher limits
- Use heartbeat wisely - the 1 req/s heartbeat limit is intentional; send exactly one per second