REST Endpoint Limits
| Category | Rate Limit | Scope |
|---|
| Trading (orders, cancel) | 10 req/sec | per API key |
| Order queries | 5 req/min | per API key |
| Portfolio/Balances | 2 req/min | per API key |
| List instruments | 1 req/min | per IP |
| Single instrument | 1 req/5sec | per IP |
| API key management | 1-5 req/min | per user |
WebSocket Limits
| Limit | MVP Value |
|---|
| Connections | 1 per API key |
| Subscriptions | 10 instruments |
| Reconnect cooldown | 5 seconds |
All REST responses include rate limit headers:
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1673625600
| Header | Description |
|---|
X-RateLimit-Limit | Maximum requests allowed in the time window |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when the limit resets |
Rate Limit Exceeded
When you exceed a rate limit, you’ll receive a 429 Too Many Requests response:
{
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded. Try again in 5 seconds.",
"retry_after": 5
}
Best Practices
Check remaining requests before making calls:
response = requests.get(url, headers=headers)
remaining = int(response.headers['X-RateLimit-Remaining'])
if remaining < 2:
reset_time = int(response.headers['X-RateLimit-Reset'])
sleep_time = reset_time - time.time()
time.sleep(sleep_time)
Implement Exponential Backoff
def make_request_with_backoff(url, max_retries=5):
for attempt in range(max_retries):
response = requests.get(url)
if response.status_code != 429:
return response
retry_after = int(response.headers.get('Retry-After', 2 ** attempt))
time.sleep(retry_after)
raise Exception("Max retries exceeded")
Batch Operations
Instead of polling individual orders:
# Bad - 100 requests
for order_id in order_ids:
get_order(order_id)
# Good - 1 request
get_open_orders() # Returns all at once
Use WebSocket for Real-Time Data
# Bad - Polling every second (60 req/min - exceeds limit!)
while True:
get_instrument_price(instrument_id)
time.sleep(1)
# Good - WebSocket subscription (1 connection)
ws.subscribe(instrument_id) # Real-time updates
Cache Static Data
# Cache instruments (they don't change frequently)
instruments = get_instruments() # 1 req/min limit
cache_instruments(instruments, ttl=300) # Cache for 5 minutes
Requesting Higher Limits
If you have a legitimate use case requiring higher limits:
- Demonstrate usage - Trade actively for 30+ days
- Contact support - Email [email protected]
- Provide details:
- Your API key ID
- Current usage patterns
- Why you need higher limits
- Your trading strategy overview
Limits may be increased for established, legitimate users on a case-by-case basis.
Fair Use Policy
Rate limits are in place to:
- Ensure system stability for all users
- Prevent abuse and excessive load
- Maintain fair access to market data
- Protect against accidental runaway scripts
Repeated violations of rate limits or attempts to circumvent them may result in API key suspension.