Rate Limits
Requests per minute by plan, the headers that report them, and how to handle 429.
Diese Seite gibt es noch nicht auf Deutsch, deshalb siehst du sie auf Englisch.
Limits
Each API key has a budget of requests per minute, set by your organization's plan:
| Plan | Requests per minute |
|---|---|
| Free | 60 |
| Paid | 600 |
The window is a fixed calendar minute. Limits apply per API key, so two keys each have their own budget. Subscriptions from before the current pricing keep their limit; GET /api/v1/me shows the limit of your key.
MCP tool calls count against the same limits: per API key, or, for assistants signed in with OAuth, per connected app and user.
Response headers
Every response carries the current state:
| Header | Description |
|---|---|
X-RateLimit-Limit | Requests allowed per minute |
X-RateLimit-Remaining | Requests left in the current minute |
X-RateLimit-Reset | Unix time (seconds) when the minute ends |
When you hit the limit
The API answers 429 with a Retry-After header in seconds:
{
"error": {
"type": "rate_limit_error",
"code": "rate_limited",
"message": "Too many requests, retry after the time in Retry-After",
"docUrl": "https://feedhorizon.com/docs/api/errors#rate_limit_error",
"requestId": "req_m2x81a0kfd3h9s"
}
}async function apiCall(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch(url, options);
if (res.status !== 429) return res;
const wait = Number(res.headers.get('Retry-After') ?? 60);
await new Promise((r) => setTimeout(r, wait * 1000));
}
throw new Error('Rate limit: retries exhausted');
}Tips
- Slow down when
X-RateLimit-Remaininggets low instead of waiting for a 429. - Use webhooks instead of polling post status.
- Send writes with an
Idempotency-Key, so a retry after a 429 or a timeout never creates a duplicate.