Rate Limits & Quotas
Limits are enforced per API key. Three dimensions apply: a request rate (per minute), a monthly quota (total calls), and the maximum top_k you can request per call.
How limits apply#
Limits are tracked per API key, not per IP — so your throughput is your own, independent of where requests originate. Each call to POST /v1/retrieve counts against both your rate limit and your monthly quota.
Your key also has a maximum top_k you can request. If you send a top_k above that maximum, the API clamps it down rather than rejecting the call.
Plan limits#
API access is paid; a key is provisioned by our team on one of the plans below. If your workload needs more, tell us your expected volume and we’ll raise the limits on your key.
When you hit a limit#
Exceeding your per-minute rate or your monthly quota returns 429 Too Many Requests in the standard error envelope. (An over-limit top_k is clamped instead, never rejected.)
{
"success": false,
"error": {
"statusCode": 429,
"message": "Rate limit exceeded",
"error": "Too Many Requests",
"path": "/v1/retrieve",
"timestamp": "2026-05-30T12:00:00.000Z"
}
}Handling 429s#
Back off and retry with exponential backoff and jitter. A simple approach:
async function retrieveWithRetry(body, { maxRetries = 4 } = {}) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch("https://api.focusalpha.ai/v1/retrieve", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.FOCUSALPHA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (res.status !== 429) return res;
// exponential backoff with full jitter
const delay = Math.random() * Math.min(1000 * 2 ** attempt, 15000);
await new Promise((r) => setTimeout(r, delay));
}
throw new Error("Rate limit: retries exhausted");
}filters so each call does more useful work. If you consistently need more headroom, talk to us about a higher plan.