title: Rate limits and quotas description: Read your remaining allowance from every response, so you never discover a limit by hitting it.
The most-cited complaint about market-data APIs is finding out where the limits are by crashing into them. So your quota state is on every response, not buried in a dashboard you have to remember to check.
Two windows
Live keys are checked against both:
| Window | Purpose | |---|---| | Per minute | Burst control | | Per 30 days | Volume allowance |
Your account's numbers for each are on your dashboard and on the pricing page.
The headers
Every response carries three headers:
| Header | Meaning |
|---|---|
| X-RateLimit-Limit | The ceiling for the window nearest exhaustion |
| X-RateLimit-Remaining | Requests left in that window |
| X-RateLimit-Reset | Unix seconds when that window resets |
They describe whichever window is closer to exhaustion, because that is the one you are about to hit. If you are at 3 of 60 remaining this minute but 8,000 of 10,000 remaining this month, the headers describe the minute.
Read them on every response, not just on failures. That is what lets you slow down before you are rejected rather than after.
Sandbox has its own allowance
A sandbox request never touches your live allowance. It cannot consume, race against, or otherwise perturb it.
Sandbox is not unmetered, though. It runs through the same limiter against
its own windows — 60 requests per minute and 50,000 per 30 days, keyed
by account — and a sandbox key that exceeds them gets the same 429 a live key
would.
So read the headers on sandbox responses the way you read them on live ones: they report your real remaining sandbox allowance, and they are the only warning you get before a rejection. What they will not tell you is anything about your live allowance — the two are counted separately. Issue a live key and read its headers for that.
When you exceed a limit
You get rate_limited with HTTP 429, the quota
headers, and a Retry-After header.
Respect Retry-After. Retrying sooner will not succeed and consumes the burst
window that your legitimate traffic needs.
HTTP/1.1 429 Too Many Requests
Retry-After: 27
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1784500427
Staying inside the allowance
- Bulk over loops.
/v1/prices/bulkaccepts many instrument ids in one request. Fetching 200 instruments one at a time costs 200 requests; the bulk route costs far fewer. This is the single biggest saving available to most consumers. - Widen date ranges, not request counts. One request for a year of daily bars costs the same as one request for a day.
- Cache what does not change. Historical bars for a closed session are
final unless a corporate action restates them, and
meta.actionSetVersiontells you when that happened. Re-fetching yesterday's closes every minute is pure waste. - Back off on 429 and on 5xx. Exponential backoff with jitter, honouring
Retry-After. - Develop against sandbox. It costs you nothing.
Watching usage over time
Your dashboard shows requests over time, a breakdown by endpoint, and your remaining allowance. Failed requests are recorded too - a usage view that only showed successes would be exactly the view that cannot explain why an integration broke.