Anthropic Claude · HTTP 429 · rate_limit_error

Claude API: 429 rate_limit_error

A 429 rate_limit_error from the Claude API means your organization exceeded an Anthropic limit: requests per minute, input or output tokens per minute, or the monthly spend limit. If retry-after is present, wait that many seconds. If it is absent and the error details say enforced_spend_limit_reached, retries will fail until next month or a higher tier.

Updated: · based on the official documentation of Anthropic Claude

Which limits Anthropic counts

RPM, ITPM (input tokens per minute) and OTPM (output tokens per minute), per model class. Limits follow a token bucket that refills continuously rather than resetting every minute, so 60 RPM can behave like one request per second.

There are acceleration limits for sharp traffic increases and a monthly spend limit per tier; when it is reached, usage pauses until 00:00 UTC on the 1st of the next month.

Response headers

retry-after gives the seconds to wait; it is not sent on every 429 and never on a spend-limit 429. anthropic-ratelimit-requests-remaining, anthropic-ratelimit-tokens-remaining and the …-reset headers show what is left and when it refills.

What to do

Wait for retry-after, retry with a capped backoff and ramp traffic gradually. Use prompt caching: on most models cache reads do not count toward ITPM. Request a higher tier in the Anthropic console.

If a direct Anthropic account is unavailable, connect Claude through API429: OpenAI-compatible format, one key for Claude, GPT and Gemini. Handle 429 and Retry-After there as well.

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

Why do I get 429 at low load?

Limits refill continuously, so a short burst can exceed them even when the per-minute average is low.

What is enforced_spend_limit_reached?

The tier’s monthly spend limit is reached. The 429 arrives without retry-after and keeps failing until next month or a tier upgrade.

Does prompt caching help?

Yes: on most models cached input tokens do not count toward the input-tokens-per-minute limit.

Can I use the Claude API from an unsupported country?

Anthropic does not serve unsupported countries directly; API429 offers Claude through one OpenAI-compatible key.

Sources

Next steps

Other API errors

Telegram