Rate limits
Each plan has a daily quota and a per-minute limit. Both apply to your API key, and every call counts as one request.
Limits per plan
| Plan | Requests / day | Requests / minute | Stream proxy | Price |
|---|---|---|---|---|
| Free | 20 | 10 | No | $0 |
| Starter | 3,000 | 60 | Yes | $12/month or $60/6 months |
| Pro | 20,000 | 300 | Yes | $22/month or $110/6 months |
| Business | 500,000+ | Custom | Yes | From $100/month |
| 3-Day Pass | 2,000 | 60 | Yes | $1 for 3 days |
Business plans can have custom limits. Compare plans.
How limits work
- Per day: counted per UTC day and reset at 00:00 UTC. Unused requests don't roll over.
- Per minute: counted per clock minute (UTC).
- Rejected calls (401, 403, 429) don't use up your quota.
- The stream proxy counts each HTTP request. Video players fetch in chunks, so one playback is several requests.
- When a paid plan ends, the same key keeps working on Free limits.
Rate limit headers
| Header | Meaning |
|---|---|
| X-RateLimit-Limit | Requests allowed per day on your plan. |
| X-RateLimit-Remaining | Requests left today. |
| X-RateLimit-Reset | Unix time (seconds) when the daily quota resets, always 00:00 UTC. |
| X-RateLimit-Limit-Minute | Requests allowed per minute. |
| X-RateLimit-Remaining-Minute | Requests left in the current minute. |
429 Too Many Requests
Going over the per-minute limit:
HTTP/1.1 429 Too Many Requests
Retry-After: 34
Content-Type: application/json
{
"error": "rate_limit_exceeded",
"detail": "Your free plan allows 10 requests per minute. Slow down and retry in 34s.",
"limit": 10,
"window": "minute",
"retry_after_seconds": 34,
"upgrade_url": "https://animedoc.cloud/pricing"
}Using up the daily quota:
{
"error": "daily_quota_exceeded",
"detail": "Your starter plan's 3,000 requests/day are used up. The quota resets at 2026-10-05 00:00 UTC, or upgrade for more.",
"limit": 3000,
"window": "day",
"resets_at": "2026-10-05T00:00:00+00:00",
"retry_after_seconds": 41250,
"upgrade_url": "https://animedoc.cloud/pricing"
}Handling 429 in code
async function animedoc(path, init = {}, attempt = 1) {
const res = await fetch("https://api.animedoc.cloud" + path, {
...init,
headers: { "X-API-Key": process.env.ANIMEDOC_API_KEY, "Content-Type": "application/json", ...init.headers },
});
if (res.status === 429 && attempt < 3) {
const body = await res.json();
if (body.error === "daily_quota_exceeded") throw new Error("Daily quota used up until " + body.resets_at);
const wait = Number(res.headers.get("Retry-After") || 1);
await new Promise((r) => setTimeout(r, wait * 1000));
return animedoc(path, init, attempt + 1);
}
return res;
}Cache search and details results on your side (they change rarely) to stay well under your limits. Don't cache Media Sources URLs: they expire.