LLM API Rate Limits: 13 Providers Compared, 2 SDKs Never Retry a 429
Contents
Four of the thirteen LLM APIs surveyed here (ten vendors plus Bedrock, Vertex AI and Azure OpenAI) tell you your remaining budget on every response, Mistral sends a single remaining count, and eight say nothing until the request fails. “429” is four different situations: a throttle to retry, an acceleration limit to slow down for, a quota or spend cap not to retry at all, and an overload reported as 429, 503, or 529 depending on the vendor. And the client decides more than the vendor: the OpenAI, Anthropic and Groq SDKs retry a 429 twice and give up on any Retry-After above 60 or 120 seconds, while the Google GenAI and Mistral SDKs ship with retries off. This is the cross-vendor reference: dimensions, which tokens count, headers, 429 semantics, and what each official SDK does, read from its source.
TL;DR
- LLM APIs throttle on requests and tokens per minute; Anthropic splits input and output, DeepSeek caps concurrency only.
- OpenAI, Azure and Bedrock debit
max_tokensup front; Anthropic exempts cache reads; xAI counts reasoning; Bedrock burns 10 quota tokens per Claude 5 output token. - OpenAI, Anthropic, Groq and Azure return remaining and reset headers on every 200; eight APIs document none.
- google-genai and Mistral SDKs do not retry a 429 by default; OpenAI, Anthropic and Groq retry twice and cap Retry-After at 60 or 120 seconds.
What do RPM, TPM and the other limits mean?
They are all ceilings on how much you may send in a window, and each provider picks its own set:
| Group | Terms | What they mean, and who uses them |
|---|---|---|
| Request meters | RPM, RPD, RPS, concurrency | Requests per minute or per day, counted one per call whatever its size. RPS is usually RPM divided by 60, enforced as a burst guard (xAI, Alibaba, Mistral, Azure). Concurrency counts requests in flight rather than per window, and is DeepSeek’s only limit |
| Token meters | TPM, TPD, ITPM, OTPM, burndown rate | Tokens per minute or per day, split by some providers into input (ITPM) and output (OTPM). A burndown rate multiplies output tokens before they are charged against the quota (Bedrock). Which tokens count at all is the provider’s choice, covered next |
| Meters for other units | IPM, audio seconds, OCR pages | Images per minute on image models (OpenAI, Gemini), audio seconds per hour or day (Groq, Mistral), pages per minute for document OCR (Mistral) |
| How the window is enforced | Token bucket, acceleration limit | A token bucket refills continuously rather than resetting on the minute, so a burst can empty it under the per-minute total (Anthropic; Alibaba and Azure describe the same effect). An acceleration limit is a separate check on how fast usage grows, hit by a sudden ramp even under the limit (Anthropic, OpenAI’s slow_down) |
| What sets your numbers | Tier, spend cap or quota, provisioned capacity | A tier is the bracket that sets the meters above, and it moves up with paid usage or history, not with credit top-ups. A spend cap or daily quota is a ceiling on money or volume, not a rate, so waiting a minute does not help. Provisioned capacity is reserved throughput billed per unit per hour (Bedrock and Vertex AI Provisioned Throughput, Azure PTU), where a 429 means the reservation is full rather than a quota exhausted |
The number on the page is a ceiling for the window, not an allowance: Anthropic notes that 60 RPM “might be enforced as 1 request per second”, Azure that “a burst within a 1-second or 10-second window can trigger a 429 even if the per-minute total is within limits”.
What do LLM APIs rate-limit on?
Requests and tokens per minute almost everywhere; the three clouds do not simply relay their vendors’ rules. Definitions are the providers’ own, from the linked pages as they read on 2026-09-03 and 2026-09-04.
| Provider | Dimensions | How limits grow | Source |
|---|---|---|---|
| OpenAI | RPM, RPD, TPM, TPD, IPM, audio minutes per minute; Batch API queue by queued input tokens | Tiers 1 to 5 by cumulative payment | rate limits |
| Anthropic | RPM, ITPM, OTPM per model class; token bucket; acceleration limits | Start, Build, Scale tiers by usage history | rate limits |
| Google Gemini | RPM, TPM (input), RPD; IPM on image models | Free, then Tiers 1 to 3 with spend limits per 10 minutes | rate limits |
| xAI | RPS (RPM / 60) and TPM per model | Tiers 0 to 4 plus Enterprise | rate limits |
| Alibaba Model Studio | RPM and TPM per model, with RPS = RPM / 60 and TPS = TPM / 60 as burst guards | Per model; batch exempt for some models | rate limits |
| DeepSeek | Concurrency only: 500 connections on V4 Pro, 2,500 on V4 Flash | Fixed per model | rate limit |
| Mistral | RPS, tokens per minute, tokens per month, per model and workspace | Tiers 1 to 4 by cumulative billing; “Adding credits does not raise your rate limits” | usage and limits, help center |
| MiniMax | RPM and TPM per model; MiniMax M3 at 200 RPM and 10M TPM | Contact sales | rate limits |
| Moonshot Kimi | Concurrency, RPM, TPM, TPD; Tier 0 is 1 concurrent and 3 RPM, Tier 5 is 100 and 300 | Six tiers by cumulative recharge, $1 to $3,000 | limits |
| Groq | RPM, RPD, TPM, TPD, ITPM, OTPM, audio seconds per hour and day | Per model | rate limits |
| Amazon Bedrock | RPM, TPM, TPD per model per region; TPD defaults to TPM x 1,440 | Service Quotas, raised on request; new accounts start reduced | quotas |
| Google Vertex AI | No per-project number on pay-as-you-go: a shared pool where “your organization’s historical spend determines your Usage Tier and baseline throughput (TPM)”, with best-effort bursting | Usage tier by spend; Provisioned Throughput “provides isolation from the shared PayGo pool” | Google Cloud blog |
| Azure OpenAI | TPM assigned per deployment, RPM derived from it (6 RPM per 1,000 TPM on older models, 1 RPM per 1,000 TPM on current ones); PTU deployments limited by utilization | Quota tiers 0 to 6, auto-upgraded | quotas and limits, quota management |
Two rows are not minute windows at all. DeepSeek caps open connections and, under load, keeps a request open with empty lines (or : keep-alive comments on a stream) for up to 10 minutes rather than rejecting it. Vertex AI on pay-as-you-go has no quota number to read: a 429 means the shared pool was short at that moment.
Which tokens count toward the limit?
Not the same tokens you are billed for, and the difference decides whether your real capacity is a fraction or a multiple of the number on the page:
| Provider | What counts toward the token limit | Consequence |
|---|---|---|
| OpenAI | The greater of max_tokens and an estimate from the prompt, debited on arrival: “If you set max_tokens too high, your usage can be overestimated, even if the actual response is much shorter” (cookbook) | A 4,000-token max_tokens on a 50-token answer spends 4,000 of your TPM |
| Azure OpenAI | An estimate from “prompt text and count, the max_tokens parameter setting, the best_of parameter setting”, based partly on character count; on PTU deployments “cached tokens receive a 100% discount” (quota guide) | “A rate limit can be triggered prior to what might be expected”; an unset max_tokens is estimated for you |
| Amazon Bedrock | ”Total input tokens + max_tokens” deducted at the start, corrected at the end to InputTokenCount + CacheWriteInputTokens + (OutputTokenCount x burndown rate), cache reads exempt. Burndown is 5x on Claude 4.7 and earlier, 10x on Sonnet 5, Opus 5, Fable 5.1 and the GPT-5.6 models, 15x on Claude 4.8 (token counting) | The documented example: 1,000 input and 100 output tokens on a 5x model consume 1,500 quota tokens and bill 1,100 |
| Anthropic | ITPM counts input_tokens and cache_creation_input_tokens; cache_read_input_tokens “do NOT count toward ITPM”. OTPM counts actual output; “max_tokens does not factor into OTPM” (docs) | The documented example: 2M ITPM at an 80% cache hit rate handles 10M input tokens a minute |
| xAI | ”All tokens consumed by a request count toward the TPM limit: prompt tokens (text, image, and audio), completion tokens, reasoning tokens (on reasoning models), cached prompt tokens” | Reasoning spends TPM on tokens you never see; caching does not raise throughput |
| Google Gemini | Input tokens | Output length does not draw down the limit |
| Alibaba, Mistral, MiniMax | Input plus output | |
| Kimi, Groq, DeepSeek, Vertex AI | Not stated | Groq meters ITPM and OTPM separately; DeepSeek has no token limit; Vertex AI publishes only a usage-tier baseline |
The same request is a different size against every limit, 800 to 6,000 tokens in the example above, so a router that spreads one workload across vendors needs a meter per vendor.
Which headers does each provider return?
Four APIs put the limit state in every response, Mistral sends one field, and the other eight leave you to count.
| Provider | Headers on a normal response | Format notes |
|---|---|---|
| OpenAI | x-ratelimit-limit-requests, x-ratelimit-limit-tokens, x-ratelimit-remaining-requests, x-ratelimit-remaining-tokens, x-ratelimit-reset-requests, x-ratelimit-reset-tokens, plus the -project-tokens trio | Reset is “the time until the rate limit resets”; Retry-After on 429 |
| Azure OpenAI | The same six x-ratelimit-* names on every call; retry-after-ms and retry-after on 429 | A x-ratelimit-limit-tokens below your configured TPM means a “temporary rate limit adjustment” is active |
| Anthropic | anthropic-ratelimit-requests-{limit,remaining,reset}, the same trio for tokens, input-tokens and output-tokens, plus anthropic-priority-* and anthropic-fast-* where those tiers apply | Reset in RFC 3339; remaining rounded to the nearest thousand; the tokens-* trio shows “the most restrictive limit currently in effect” |
| Groq | x-ratelimit-limit-requests (daily), x-ratelimit-limit-tokens (per minute), x-ratelimit-remaining-*, x-ratelimit-reset-*; “always included” | Reset as durations, "2m59.56s", "7.66s"; retry-after in seconds, 429 only |
| Mistral | X-RateLimit-Remaining | |
| Gemini, xAI, Alibaba, DeepSeek, MiniMax, Kimi, Bedrock, Vertex AI | None documented | Gemini, Alibaba and Bedrock name the reason in the error body; Kimi documents Retry-After on overload; the AWS SDKs read x-amz-retry-after in milliseconds where a service sends one |
Three formats for one field is the practical problem: OpenAI’s duration, Anthropic’s timestamp and Groq’s 2m59.56s need three parsers, which is one reason the SDKs read only retry-after. Two intermediaries were measured on 2026-09-03 with one request each. A large multi-provider aggregator returned no rate-limit header at all on a 200, reserving them for 429 responses; the Synthorai gateway returned x-ratelimit-remaining-requests and x-ratelimit-reset-requests alongside the request’s cost.
What does a 429 mean, and should you retry?
It depends on which of four things it is, and only two of them deserve a retry:
| Meaning | Retry? | How each provider spells it |
|---|---|---|
| Throttle: you exceeded a limit | Yes, after Retry-After or backoff | OpenAI and Anthropic 429 rate_limit_error, Anthropic with retry-after; Gemini and Vertex AI 429 RESOURCE_EXHAUSTED, on Vertex AI meaning the shared pool was short; Kimi rate_limit_reached_error; Bedrock ThrottlingException, plus ModelNotReadyException retried by the SDK up to 5 times; Azure “Rate limit is exceeded”; xAI RateLimitError; Alibaba “Requests rate limit exceeded”; DeepSeek and Mistral 429 |
| Acceleration: you ramped up too fast | Slow the ramp, then retry | OpenAI slow_down; Anthropic “acceleration limits”; Alibaba “Request rate increased too quickly”; Azure, a burst inside a 1-second or 10-second window |
| Quota or spend cap: nothing frees up by waiting | No; fix billing or wait for the reset date | OpenAI insufficient_quota, credit_balance_exhausted, organization_spend_limit_exceeded; Anthropic enforced_spend_limit_reached with no retry-after, while your own spend limit is a 400; Gemini quota_exceeded (daily); Kimi exceeded_current_quota_error; Bedrock 400 ServiceQuotaExceededException; aggregator and DeepSeek 402. On Azure, quota is assigned at deployment time, so exhausting it is not a 429 |
| Overload: the provider’s capacity, not yours | Yes, with backoff | OpenAI 503 server_is_overloaded; Anthropic 529 overloaded_error; Gemini 503 UNAVAILABLE; Kimi 429 engine_overloaded_error with Retry-After; Bedrock 503 ServiceUnavailableException and 529 overloaded_error; Azure “System is experiencing high demand”, a “temporary rate limit adjustment” of the shared pool, or PTU at 100% utilization with retry-after-ms; DeepSeek 503 |
The trap is in the third row. Anthropic’s spend-cap 429 carries the same rate_limit_error type as a throttle, and the docs say “Retrying, including the SDKs’ automatic retries, fails until access resumes.” OpenAI’s insufficient_quota is a 429 too. A client that branches on the status code alone retries both, and every official SDK does, as the next section shows. Branch on the error code, and treat a 429 without Retry-After as a hint that waiting will not help.
The fourth row is where the clouds differ. Azure’s troubleshooting guide says it plainly: “Many customers misinterpret capacity-related 429s as quota problems, leading to incorrect remediation.” On Azure, a 429 with x-ratelimit-limit-tokens lower than your configured limit is the shared pool protecting itself; on Vertex AI every pay-as-you-go 429 is that; on Bedrock the same condition is a 503 or 529, never a ThrottlingException. Through an aggregator it shows up in the body: one 429 during the header measurement arrived wrapped as provider_error_code: insufficient_quota, limit_source: upstream_provider_shared_pool. The status said throttle; the body said someone else’s quota.
What does your SDK do with a 429?
It depends on the SDK, and two of the most used ones do nothing. Read from each official client’s own source on 2026-09-04, not from its documentation:
| SDK | Retries by default | Retried statuses | Backoff | Retry-After handling |
|---|---|---|---|---|
| openai-python (also Azure OpenAI) | 2 | 408, 409, 429, 5xx, or whatever x-should-retry says | min(0.5 × 2^n, 8) s with jitter | Reads retry-after-ms, then retry-after as seconds or a date; above 120 s it does not retry at all |
| anthropic-sdk-python, groq-python | 2 | same | same | Same parsing; above 60 s the header is ignored and the backoff formula is used |
| openai-node, anthropic-sdk-typescript | 2 | same | same | Same; above 60 s falls back to the default backoff |
| google-genai (Python, Gemini API and Vertex AI) | 0: retry_options defaults to None, which resolves to a single attempt | When enabled: 408, 429, 500, 502, 503, 504 | When enabled: 5 attempts, 1 s doubling to 60 s with jitter | Does not read Retry-After |
| mistralai (Python) | 0: retry_config defaults to unset | When configured: 429, 500, 502, 503, 504 | When configured: 500 ms × 1.5^n up to 60 s, 1 h total | Honors any Retry-After, seconds or date |
| boto3 (Bedrock) | Legacy mode: 5 attempts including the first; standard mode: 3 | ThrottlingException and kin, 429, 5xx | Base factor 2, 20 s cap in standard mode. The 2026 behavior (opt-in via AWS_NEW_RETRIES_2026=true) uses full jitter, a 1,000 ms base for throttling and a retry token bucket | No Retry-After; the 2026 behavior reads x-amz-retry-after in milliseconds, clamped to the backoff plus 5 s |
| xai-sdk (Python, gRPC) | 5 attempts, only for UNAVAILABLE | RESOURCE_EXHAUSTED, the gRPC 429, is not retried | 0.1 s doubling to 1 s | n/a |
| dashscope (Alibaba) | 0 on HTTP status; one resend if a pooled connection drops before any bytes arrive | |||
| DeepSeek, Kimi, MiniMax | No first-party chat SDK; DeepSeek’s docs say to “use the OpenAI/Anthropic SDK” with a different base URL |
Three things follow. First, a 429 from Gemini, Vertex AI or Mistral reaches your code on the first occurrence unless you passed retry options; the google-genai source comment that the client “will retry 4 times” describes the enabled configuration, not the default. Second, the Retry-After ceilings work against the long waits a vendor actually asks for: Anthropic’s SDK, asked to wait 90 seconds, ignores the header and comes back in under 8; OpenAI’s, asked to wait 150, stops retrying. Third, the SDKs generated by Stainless (the code generator behind the OpenAI, Anthropic and Groq clients) obey an undocumented x-should-retry header before they look at the status code, and retry-after-ms before retry-after, so a vendor or a gateway can steer retries without changing a status code.
None of them distinguish a spend-cap 429 from a throttle. Two retries of an insufficient_quota response cost a few seconds each, but a fleet doing that at scale is a self-inflicted burst.
How does a gateway change the picture?
A gateway is the one place where all of this can be handled once: upstream it reads whichever header each vendor sends, so the three reset formats and the four 429 meanings are its problem rather than every client’s; downstream it presents one header set and one error shape, which is what the measured Synthorai headers above are. What a gateway cannot do is change vendor accounting: behind OpenAI a client’s max_tokens still debits TPM up front, behind Bedrock a Claude output token still burns ten. And a gateway that pools many clients onto one vendor key reaches that vendor’s acceleration limit sooner than any single client would, which is the case for per-key buckets rather than one shared counter.
FAQ
Does max_tokens count toward the rate limit?
On OpenAI, Azure OpenAI and Bedrock, yes: max_tokens is debited when the request arrives, so an oversized value wastes TPM even if the answer is short; Bedrock corrects the deduction when the response finishes. On Anthropic, no: OTPM counts the tokens actually generated and max_tokens “does not factor” in.
Do cached tokens count toward the rate limit?
Not on Anthropic, Bedrock or Azure PTU deployments, where cache reads are excluded. On xAI they count in full. OpenAI and Gemini do not say.
Is Retry-After always sent with a 429?
No. OpenAI, Azure (as retry-after-ms) and Groq send it on throttles, Anthropic on throttles but not on the spend cap, Kimi and Bedrock only on overload. Gemini, Vertex AI, xAI, Alibaba, DeepSeek and MiniMax document none, so a client needs its own backoff for those.
Why did my SDK not retry a 429?
If it is the Google GenAI or Mistral Python SDK, retries are off by default: pass retry_options or a RetryConfig. If it is the OpenAI Python SDK and the server asked for more than 120 seconds, the SDK deliberately does not retry. If the 429 is a quota or spend cap, not retrying was the right outcome.
Related: billing units field guide, long-context pricing tiers, token usage anatomy, gateway cache audit.