AnyRouter

Rate Limits

AnyRouter's per-IP and per-key rate limits, how tiers are picked, what 429 vs 403 mean, and how to handle them in your client.

Agent loops and burst traffic can hammer an endpoint into a wall of 429s if the limits aren't clear. AnyRouter applies request-rate limits at two layers — a per-IP cap for anonymous traffic and a per-API-key cap for authenticated traffic — enforced over a sliding 60-second window using Cloudflare's native rate-limiting bindings. There is no daily quota on any traffic (except the Go plan's per-request-window cap on paid models, below). The free tier (anyrouter/free and *:free models) has no daily cap and uses its own generous per-minute limit.

Overview

CallerTierLimit
Anonymous (no API key)per-IP300 req / 60s
API key, free-tier model (anyrouter/free or *:free), any planfree-model2400 req / 60s
API key, plan = go, paid modelgo60 req / 60s (also capped at 3,000 req per rolling 5-hour window)
API key, plan = free or payg, paid modelpaid-model600 req / 60s
API key, plan = pro, paid modelpro1200 req / 60s
API key, plan = pro_plus or max, paid modelpower1800 req / 60s
API key, plan = enterprise (any model)enterprise2400 req / 60s
API key, POST /api/v1/decisions (any model, any plan)decision60 req / 60s

Free-model requests use the 2400/min tier on every plan, Go included, and do not count toward Go's 5-hour window. Go's 60/min and 5-hour limits apply to paid models only.

The X-RateLimit-Tier value for Pro paid-model traffic is pro; for Pro+ and Max it is power — legacy identifiers kept for backward compatibility. Account plan names are Free, Go, Pro, Pro+, and Max. See Pricing & Plans.

Why the split: free models get a generous per-key limit with no daily cap, so agent loops can run freely. Paid models are billed per token — your spend naturally regulates volume, so we lift the per-minute cap on Pro and above. Go keeps a tighter per-minute and 5-hour window cap on paid models since it's the entry paid tier.

Your account plan (free / go / pro / pro_plus / max / enterprise) determines your rate tier for paid-model traffic. A Free user calling a paid model uses the paid-model tier at 600/min; Go is capped at 60/min (plus a 3,000 req/5h window), Pro at 1200/min, and Pro+ / Max at 1800/min. Free-tier models run at the 2400/min free-model tier on every plan, with no daily cap.

How it works

Free models have no daily cap

anyrouter/free and any model suffixed with :free have no per-account daily cap and do not use Go's 5-hour window. They share one limit of 2400 requests per minute per API key on every plan. See Free Tier.

Decisions: free, no plan quota, fair-use burst cap

Decision models through anyrouter/decision are free on every plan, Free included. They need no credits and no BYOK key, and they have no daily or plan quota. "Unlimited" means exactly that: there is no plan quota.

Every request to POST /api/v1/decisions (or /api/v1/systemone) uses its own per-key fair-use burst cap of 60 requests per minute, on every plan. That cap stops one runaway script from flooding the shared decision models. It has its own counter, so decision traffic never uses up your chat rate limit, and it does not count toward Go's 5-hour window. A tripped cap returns 429 rate_limit_exceeded with Retry-After: 60 and X-RateLimit-Tier: decision.

Response headers

Every API response — including GET /api/v1/health, GET /api/v1/models, GET /api/v1/credits, error bodies, and successful completions — carries:

HeaderMeaning
X-RateLimit-LimitPer-window request cap for the tier you hit
X-RateLimit-WindowWindow length in seconds (always 60)
X-RateLimit-TierOne of ip, free-model, paid-model, go, pro, power, enterprise, decision, or starter-window (Go's 5-hour window cap — see below)
RateLimit-LimitIETF draft header — same number as X-RateLimit-Limit
RateLimit-PolicyIETF draft policy, e.g. 300;w=60 (cap ; window seconds)

The per-minute tier does not emit X-RateLimit-Remaining / X-RateLimit-Reset — the counter is not exposed by the edge limiter. Go's 5-hour window on paid models does emit them, along with the matching RateLimit-Remaining / RateLimit-Reset (window 18000, tier starter-window).

When you hit the cap, the response is HTTP 429 with a Retry-After: 60 header and a body of {"error": {"code": "rate_limit_exceeded", "message": "Rate limit exceeded for your API key — …"}}.

429 vs 403 — don't confuse them

AnyRouter returns 429 for two distinct rate-limit scenarios, each with its own error.code: rate_limit_exceeded (per-key cap) and ip_rate_limit_exceeded (anonymous IP cap). If you see a different status:

Statuserror.codeSourceWhat it means
429rate_limit_exceededAnyRouterYou hit the per-key limit. Back off Retry-After seconds.
429ip_rate_limit_exceededAnyRouterAnonymous IP hit 300/min. Sign in or send an API key.
403upstream_403Upstream providerThe model provider denied the call — geo block, policy violation, provider-side abuse heuristic. Not retryable via simple backoff.
401upstream_401Upstream providerBYOK credential rejected upstream. Check your key.
401invalid_api_keyAnyRouterYour AnyRouter API key is wrong or revoked.
402insufficient_balanceAnyRouterYour credit balance is empty. Top up at Credits.
502upstream_5xxUpstream providerProvider had a transient failure. Retry with jitter.

error.metadata.upstream_backend identifies the specific provider when the status is upstream_*.

Configure

Handling 429 in your client

Check error.code before deciding how to retry:

  • rate_limit_exceeded / ip_rate_limit_exceeded — Retry-After is 60 seconds. Back off and retry.
async function callWithBackoff(body: object): Promise<Response> {
  for (let attempt = 0; attempt < 5; attempt++) {
    const res = await fetch("https://anyrouter.dev/api/v1/chat/completions", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${ANYROUTER_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    })
    if (res.status !== 429) return res

    const wait = Number(res.headers.get("Retry-After") ?? 60)
    const jitter = Math.random() * 1000
    await new Promise((r) => setTimeout(r, wait * 1000 + jitter))
  }
  throw new Error("Rate-limit retries exhausted")
}

Do not treat a 429 as a permanent credential failure. Many agent loops mark keys as "exhausted" on 429 and stop using them — that's a client bug, not an AnyRouter behaviour. For per-minute 429s, the same key works again after the 60-second window.

Agent loops count every call

A single user task that triggers an agent loop can issue many HTTP requests:

  • 1 main chat/completions call
  • 1 more call per tool round-trip (one for each model turn after a tool result)
  • Optional auxiliary calls — title generation, conversation compaction, summarisation

Each is metered separately. A 5-tool task with title-gen + compaction is ~8 requests. At the 600/min paid-model tier you can sustain ~75 such tasks per minute; at the 2400/min free-model tier, ~300.

If your agent's natural request rate exceeds the tier:

  1. Call paid models (auto-promotes you to 600/min).
  2. Upgrade to enterprise for 2400/min.
  3. Add jitter and parallelism caps in your loop.

Need more headroom?

Open a request at /contact describing your workload (sustained req/min, burst pattern). Enterprise tiers are negotiated.