Concepts

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.