Rate limits
The API allows 60 requests per minute per token. The window is fixed and the budget is shared by all endpoints.
How the limit works#
- The count is per token and does not depend on the IP address.
- The count starts after authentication. A request with a wrong token does not use any budget.
- Every request counts, including a replayed idempotent request.
- The limit is one budget for the whole API. It is not a separate budget for each endpoint.
Rate limit headers#
Every response to an authenticated request carries three headers. This includes 2xx responses, 4xx responses from an endpoint, 429 responses and the 204 from DELETE /hooks/{id}.
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
The budget of the window: 60. |
X-RateLimit-Remaining |
How many requests are left in the current window after this one. It is 0 on a 429. |
X-RateLimit-Reset |
When the window resets, as a Unix timestamp in seconds. |
X-RateLimit-Reset is a point in time. The number of seconds to wait is in Retry-After.
A 401 response has no rate limit headers, because there is no token to count against.
The values are a snapshot taken at authentication. Two parallel requests can see the same X-RateLimit-Remaining. Use the value as a hint for backoff. It is not a transactional counter.
When you exceed the limit#
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1788517380
Content-Type: application/json
{"error":"Rate limit exceeded (60 requests/minute)."}
Retry-After is the number of seconds to the end of the window.
Handle a 429#
import time
import requests
def call(url, token):
while True:
response = requests.get(url, headers={"Authorization": f"Bearer {token}"})
if response.status_code != 429:
return response
time.sleep(int(response.headers.get("Retry-After", "1")))
MCP#
A tool call on the MCP server uses two requests from the same budget. See that page for the effect on throughput.