Rate limits and spend limits

Claude API · Advanced · 10 min

At scale, limits shape your architecture: queues, backoff, caching and batching all exist because of them.

Your organisation can only send so much per minute, measured per model class in three ways:

  • RPM: requests per minute.
  • ITPM: input tokens per minute.
  • OTPM: output tokens per minute, counted as tokens are actually produced.

Limits work like a token bucket: capacity refills continuously instead of resetting each minute, so a short burst can trigger a 429 even if your per-minute total looks fine. A sudden jump in traffic can also hit acceleration limits; ramp up gradually.

Your limits depend on your usage tier, which rises automatically with usage history. The Console's Limits page shows the current values. Cached input is good news here: for most models, tokens read from the prompt cache do not count toward ITPM, so caching raises your effective throughput.

Every response carries headers such as anthropic-ratelimit-requests-remaining and anthropic-ratelimit-input-tokens-reset, and a 429 usually includes retry-after (seconds to wait). Read headers with client.messages.with_raw_response.create(...) if you want to slow down before hitting the wall.

There are also spend limits: a monthly cap per tier, plus any lower cap you set yourself. A tier cap returns 429 with no retry-after and the error code enforced_spend_limit_reached; retrying will keep failing until the month resets or the tier changes, so alert a human instead. Your own cap returns a 400.

Example

import anthropic

client = anthropic.Anthropic()
raw = client.messages.with_raw_response.create(
    model="claude-opus-5-5", max_tokens=50,
    messages=[{"role": "user", "content": "ping"}],
)
h = raw.headers
print("requests left:", h.get("anthropic-ratelimit-requests-remaining"))
print("input tokens left:", h.get("anthropic-ratelimit-input-tokens-remaining"))
msg = raw.parse()                      # the normal Message object

try:
    client.messages.create(model="claude-opus-5-5", max_tokens=50,
                           messages=[{"role": "user", "content": "hi"}])
except anthropic.RateLimitError as e:
    if e.response.headers.get("retry-after") is None:
        print("Probably a spend cap: alert someone, don't retry")

Remember

  • Limits: RPM, ITPM, OTPM per model class, by usage tier
  • Token bucket: bursts can 429; ramp traffic gradually
  • Cache reads don't count toward ITPM on most models; spend-cap 429s won't clear by retrying

Check yourself

  1. A 429 arrives without a retry-after header and with error code enforced_spend_limit_reached. Best response?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: platform.claude.com/docs/en/api/rate-limits

Builds on

Unlocks

Nothing builds on this yet.