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

PlanRequests / dayRequests / minuteStream proxyPrice
Free2010No$0
Starter3,00060Yes$12/month or $60/6 months
Pro20,000300Yes$22/month or $110/6 months
Business500,000+CustomYesFrom $100/month
3-Day Pass2,00060Yes$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

HeaderMeaning
X-RateLimit-LimitRequests allowed per day on your plan.
X-RateLimit-RemainingRequests left today.
X-RateLimit-ResetUnix time (seconds) when the daily quota resets, always 00:00 UTC.
X-RateLimit-Limit-MinuteRequests allowed per minute.
X-RateLimit-Remaining-MinuteRequests 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

Retry after a per-minute limit
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.