Rate Limits
We implement rate limiting to make sure the API is responsive for all customers. The rate limits are set in a way to provide substantial functionality while trying to stifle abuse. Most times, a rate limit can be subverted by implementing a different API call or leveraging other API features (i.e., instead of polling for quotes, leverage the streaming API).
How Rate Limits Work
Two pieces of information to understand as it pertains to our limits:
- Interval: we aggregate limits over 1-minute intervals starting with the first request and reset 1 minute later
- Limit: this can vary (see categories below)
For example: With a rate limit of 120 requests per minute, if you make a /quotes request every second for a minute, you would still have 60 requests left in that minute before hitting the limit.
Should you be concerned about rate limits?: Probably not. Polling for data, while not the best solution, is reasonably supported by our APIs. The limits exist with enough headroom to get up-to-date data and still have room to make other requests. The best way to know if your application will hit the limits is to build it and scale back.
Limits
Each limit is enforced by the minute and on a per-access-token basis. As such, the limits are enforced on a per-app and per-user basis.
Standard
This includes resources in /accounts, /watchlists, /users and /orders.
This does NOT include placing orders.
Production: 120 requests per minute.
Sandbox: 60 requests per minute.
Market Data
This includes resources in /markets.
Production: 120 requests per minute.
Sandbox: 60 requests per minute.
Trading
This includes all resources in the “trade” scope.
Production: 60 requests per minute.
Sandbox: 60 requests per minute.
Headers
With each request that has a rate limit applied, a series of headers will be sent in the response. These headers should help you to gauge your usage and when to throttle your application. For example:
X-Ratelimit-Allowed: 120
X-Ratelimit-Used: 1
X-Ratelimit-Available: 119
X-Ratelimit-Expiry: 1799200800000 Too Many Requests
Confirmed via live testing: exceeding a rate limit does not return the conventional 429 Too Many Requests status. Instead, the API returns an HTTP 400 status with a plain-text (non-JSON) body:
Quota Violation: Expires <epoch-ms-timestamp>The Expires value is an epoch-millisecond timestamp, matching the semantics of the X-Ratelimit-Expiry header documented above. Note the response's Content-Type header for this case is plain/text (as actually returned by the API — this is a non-standard MIME type; the conventional value would be text/plain).
Since the status code doesn't match the documented 429, check for the literal substring Quota Violation in the response body — rather than relying on the HTTP status code alone — to reliably detect that a request was rejected for exceeding a rate limit.
This was confirmed via live testing against the Market Data category (/markets/quotes) in production, using multiple concurrent clients in a tight loop with no delay between requests.
On this page
- Rate Limits