Provisional
Rate limits
Development ceilings, cursor pagination, and a shape that rewards incremental syncs.
Development ceilingsPermalink to this section
| Window | Ceiling |
|---|---|
| Per minute | 60 requests |
| Per day | 5,000 requests |
These ceilings apply across all keys belonging to one owner, not per key, so issuing a second key does not double your allowance.
/v1/health, /v1/capabilities and /v1/openapi.json sit outside these ceilings: they are unauthenticated and unmetered, so probing them does not consume your allowance.
Staying inside the windowPermalink to this section
- A request over the ceiling returns 429. Wait before retrying rather than retrying immediately.
- Pull a full set once, then refresh incrementally rather than re-walking everything on a schedule.
- Page with limit=200 when you are walking a large set, so you spend fewer requests on the same data.
- Spread scheduled jobs across the hour instead of firing every worker on the minute.
- Treat 429 as normal traffic shaping, not an incident, and let your backoff absorb it.
PaginationPermalink to this section
List endpoints are cursor paginated. Pass the value of page.next_cursor back as the cursor parameter; a null cursor means you have reached the end. The cursor is opaque, so do not parse it, do not build page numbers on top of it and do not hold one across days.
cursor, out = None, []
while True:
params = {"q": "cpi", "limit": 200}
if cursor:
params["cursor"] = cursor
page = call("/v1/markets", params=params)
out.extend(page["data"])
cursor = page["page"]["next_cursor"]
if not cursor:
breakHistory requestsPermalink to this section
History takes days up to 365 and returns up to 2000 observations per request. Asking for a longer window does not create observations that were never recorded, so pull the window you actually need and cache it rather than re-requesting a year on every run.