429 responses, and how the live stream and MCP tool calls are metered. Read it before you build a poller or open streams.
Limits by tier
The stream column is the per-minute limit divided by 60, at least 1 and at most 20, counted per API instance.
How counting works
- Windows are calendar windows, not sliding: the minute window is the current clock minute and the day window is the current UTC day. Both reset on the boundary.
- Every request that authenticates is counted once, in both windows, before anything else happens. A request that then fails with
400or404still counts. A401does not. - The daily quota is checked before the per-minute limit.
- A request rejected with
429has already been counted. Keep sending andX-RateLimit-Remainingstays at 0 until the window resets. - The server caches some responses for a few seconds or minutes (see Data freshness). The cache sits behind authentication, so a cached response counts like any other.
Headers
Every authenticated response carries five headers, including429 responses, error responses after authentication, and the live stream’s response.
Over the limit
The body is the standard error envelope:
Retry-After seconds and retry the same request. Do not retry faster: the rejected request was counted, so a tight retry loop keeps the window full.
What counts as a request
Streams
- Opening a stream counts one request and returns the rate-limit headers with the
200. - An open stream counts one more request per minute. If the daily quota runs out while the stream is open, the stream sends an
errorevent with codedaily_quota_exceededand ends. - A key may hold at most the number of concurrent streams in the tier table, per API instance. One more returns
429 too_many_streamswithRetry-After: 60. - Streams end themselves after 45 to 55 minutes with a
reconnectevent; reconnecting counts as opening a stream.
MCP tool calls
Tool calls run through the same REST handler as your own requests, so the per-minute limit and daily quota are shared between REST and MCP. Over a limit, the tool call comes back as a tool error (isError: true) whose text is built as GET <path> answered <status> <code>: <message>, followed by Retry after <n> seconds. when the REST response carried Retry-After. An observed tool error for a missing market shows the shape: