Updated: · based on the official documentation of IETF, OpenAI, Anthropic, Google
Two different cases behind one code
A temporary rate limit: requests or tokens per minute were exceeded. It clears after a pause. Providers count limits per organization or project, so a new key in the same project usually does not help.
Exhausted quota or balance: OpenAI returns insufficient_quota or credit_balance_exhausted; Anthropic returns a monthly spend-limit 429 without retry-after. It will keep failing until you add credit or raise the limit.
How to tell them apart
Read the error type and code in the body, not only the status. Retry-After (RFC 9110) is either seconds or an HTTP date, so parse both. Anthropic sends anthropic-ratelimit-* headers and OpenAI sends x-ratelimit-remaining-requests and x-ratelimit-reset-tokens, which show which limit ran out.
What to do in code
Retry only transient errors: 429 with Retry-After, 500, 503, 529. Cap attempts, add jitter and do not nest SDK retries inside your own, or load snowballs. Failed requests also count toward per-minute limits.
Lower the rate: a queue with a concurrency cap, batching and a sensible max_tokens. When traffic jumps, ramp it up gradually — Anthropic and OpenAI apply separate acceleration limits.
If the 429 comes from API429
API429 is an API too and can return 429 when a model gets more requests than it can take. Handle it the same way: honour Retry-After and retry with a delay. With the same key you can send the request to another model straight away — change only the model field. One balance covers every model.
Retrying with Retry-After: Python example
import email.utils, os, random, time, requests
URL = "https://gateway.api429.com/v1/chat/completions"
HEADERS = {"Authorization": "Bearer " + os.environ["API429_API_KEY"]}
TRANSIENT = {429, 500, 503, 529}
def retry_after(value):
if not value:
return None
if value.isdigit():
return int(value)
return max(0, email.utils.parsedate_to_datetime(value).timestamp() - time.time())
def chat(payload, attempts=5):
for attempt in range(attempts):
r = requests.post(URL, headers=HEADERS, json=payload, timeout=120)
if r.status_code not in TRANSIENT:
r.raise_for_status()
return r.json()
wait = retry_after(r.headers.get("Retry-After"))
time.sleep(wait if wait is not None else min(60, 2 ** attempt) + random.random())
r.raise_for_status()Frequently asked questions
What does a 429 error mean in an API?
The server limits request frequency: you sent more requests or tokens per unit of time than allowed. Wait for Retry-After or retry with a growing delay.
Why does the 429 persist after waiting?
It is probably exhausted quota or balance rather than a rate limit: insufficient_quota at OpenAI, a monthly spend limit at Anthropic, 402 Insufficient Balance at DeepSeek. Top up the account.
Will a new API key help?
Usually not: Gemini, OpenAI and Anthropic count limits per project or organization, not per key.
How should I retry?
Only transient errors, with a capped number of attempts, exponential delay and jitter. If Retry-After is present, wait at least that long.
Sources
- www.rfc-editor.org/rfc/rfc6585
- www.rfc-editor.org/rfc/rfc9110
- developers.openai.com/api/docs/guides/rate-limits
- platform.claude.com/docs/en/api/rate-limits
- ai.google.dev/gemini-api/docs/rate-limits
Next steps
- OpenAI API on API429
- OpenAI API pricing comparison
- Claude Sonnet 5.5 model card
- n8n HTTP workflow integration
- Model catalog
- Quickstart