n4nAI

Comparing rate limit headers across OpenAI and Anthropic

A head-to-head comparison of rate limit headers openai anthropic: schema, reset semantics, ergonomics, and how to build resilient clients against both.

n4n Team5 min read1,050 words

Audio narration

Coming soon — every post will get a voice note here.

Rate limit headers openai anthropic expose are the primary signal your client gets to avoid 429s and schedule retries. They look similar at a glance but diverge in naming, granularity, and reset semantics, which matters when you write a single HTTP layer for both providers.

Header Inventory: What Each Provider Sends

OpenAI’s chat completions endpoint returns a consistent set of x-ratelimit-* headers on every response (including the final frame of a stream). The full set for request and token resources:

x-ratelimit-limit-requests: 3500
x-ratelimit-limit-tokens: 90000
x-ratelimit-remaining-requests: 3492
x-ratelimit-remaining-tokens: 88120
x-ratelimit-reset-requests: 1700000000
x-ratelimit-reset-tokens: 1700000060
x-request-id: req_abc123

On a 429 you also get retry-after: 2 (seconds). Anthropic’s Claude API ships a leaner set:

anthropic-ratelimit-limit: 50
anthropic-ratelimit-remaining: 49
anthropic-ratelimit-reset: 60
anthropic-ratelimit-used: 1
request-id: req_01ABC

Note the absence of token-specific headers. Anthropic enforces token-per-minute limits server-side, but the visible header surface only covers request counts. If you’re tracking token burn to avoid throttling, you must maintain your own counters for Anthropic.

Streaming Caveats

OpenAI sends the rate limit headers on the HTTP response headers of the streaming request, not per chunk. Anthropic does the same. Both providers omit retry-after on successful streams; you only see it on the error response if the stream fails mid-flight. Parse headers once at stream start, not from SSE events.

Reset Semantics: Absolute vs Relative

The rate limit headers openai anthropic differ most in how they tell you when the window clears. OpenAI’s x-ratelimit-reset-requests and x-ratelimit-reset-tokens are Unix epoch seconds (absolute). Anthropic’s anthropic-ratelimit-reset is a relative delta in seconds from the time of the response.

That means parsing code must branch:

import time

# OpenAI: absolute epoch
reset_ts = int(headers["x-ratelimit-reset-requests"])
sleep_for = max(0, reset_ts - int(time.time()))

# Anthropic: relative seconds
sleep_for = int(headers["anthropic-ratelimit-reset"])

Mixing them in one retry loop without normalizing will cause either premature retries (treating epoch as delta) or massive sleeps (treating delta as epoch). I’ve seen both bugs in production.

Granularity and Capabilities

OpenAI breaks limits into two resources: request count and token count, each with its own limit, remaining, and reset. This lets you implement token-aware scheduling—e.g., pause when remaining-tokens drops below your next prompt’s estimated size even if remaining-requests is high.

Anthropic’s single request-counter header set is simpler but blind to payload size. For a gateway or proxy that aggregates many small and large calls, the lack of token headers means you must estimate token usage client-side (using a tokenizer) and risk hitting invisible token ceilings.

Both providers return retry-after on 429, but OpenAI may also return it on other errors (e.g., 500 with backlog). Anthropic’s retry-after appears only on 429 and occasionally on 529 (overloaded).

Ergonomics: Parsing and Middleware

If you use the official SDKs, you typically access headers via response.headers (Python) or response.headers (TypeScript). Neither SDK surfaces rate limit fields as typed properties, so you write the same dict access either way.

# OpenAI python SDK
resp = client.chat.completions.create(...)
lim = resp.headers.get("x-ratelimit-remaining-tokens")

# Anthropic python SDK
resp = anthropic.messages.create(...)
lim = resp.headers.get("anthropic-ratelimit-remaining")

The friction appears when you adopt generic OpenAI-compatible middleware (e.g., LangChain’s retry wrapper). It expects x-ratelimit-* and will ignore Anthropic’s anthropic-ratelimit-*. You need an adapter that maps Anthropic headers to the OpenAI key names if you want unified logic.

Cost and Quota Implications

Rate limit headers don’t directly affect price—you’re billed per token regardless. But they influence effective cost through retries and queueing. A client that ignores remaining-tokens on OpenAI can burst until a 429, then back off, adding tail latency that may breach your SLA and force you to provision a higher tier (which is a real line-item cost).

Anthropic’s hidden token limit means you might get 429s with remaining-requests still positive because you blew the token budget. Those errors surface as anthropic-ratelimit-reset small but no token context. You can’t cheaply precompute; you just eat the retry.

Latency and Throughput Management

Using the headers for client-side throttling beats naive exponential backoff. With OpenAI, a token-aware controller looks like:

class OpenAIThrottle:
    def __init__(self):
        self.tok_rem = 1e9
        self.tok_reset = 0
    def observe(self, h):
        self.tok_rem = int(h["x-ratelimit-remaining-tokens"])
        self.tok_reset = int(h["x-ratelimit-reset-tokens"])
    def can_send(self, est_tokens):
        if est_tokens > self.tok_rem:
            return max(0, self.tok_reset - int(time.time()))
        return 0

For Anthropic, you only have request granularity, so you cap concurrency at anthropic-ratelimit-remaining and rely on server-side token enforcement:

sem = asyncio.Semaphore(int(headers["anthropic-ratelimit-remaining"]))

Throughput suffers if your calls are token-heavy because you can’t see the token window; you’ll underutilize request quota waiting on 429s.

Ecosystem and Library Support

OpenAI’s header scheme has become a de facto standard; many proxies mimic x-ratelimit-* even when backend is not OpenAI. Anthropic’s scheme is proprietary but stable since mid-2023. If you build a multi-provider abstraction, the path of least resistance is to translate Anthropic → OpenAI header names internally.

When routing through a unified endpoint that fronts both providers, you may receive OpenAI-shaped headers for all models because the gateway maps backend responses. One such gateway, n4n.ai, exposes a single OpenAI-compatible endpoint across 240+ models and forwards provider cache-control hints, though rate limit header normalization depends on the implementation. The key is to verify what your gateway actually returns before writing parsing logic.

Limits and Accuracy

Both providers compute limits per organization and per model tier. OpenAI’s remaining values are exact at response time but can go negative in race conditions under high concurrency; treat them as approximations. Anthropic’s remaining is also a snapshot; if you run 50 parallel requests, the header on one response may already be stale for the others.

Neither provider guarantees the reset window is fixed; OpenAI may use sliding windows, so the epoch reset can jump forward after a burst. Anthropic’s relative reset is measured from response time and can vary per request.

Comparison Table

Dimension OpenAI Anthropic
Header prefix x-ratelimit-* anthropic-ratelimit-*
Resources exposed Requests + Tokens (separate) Requests only
Reset format Absolute Unix epoch seconds Relative seconds from response
429 retry-after Yes (seconds) Yes (seconds)
Token-level throttling Possible client-side Not possible from headers
SDK typed support None (raw headers) None (raw headers)
Multi-resource windows Independent request/token resets Single request window
Ecosystem mimicry Widely emulated Rarely emulated

Which to Choose: Verdict by Use Case

Solo OpenAI integration. Use the x-ratelimit-* headers directly. Build a token-aware scheduler; it’s the only way to maximize throughput on large prompts without 429 storms.

Solo Anthropic integration. Parse anthropic-ratelimit-remaining and anthropic-ratelimit-reset. Keep your own token estimator and set conservative concurrency. Don’t expect to see token headroom.

Multi-provider or gateway layer. Write one internal representation (e.g., limit_requests, remaining_requests, reset_requests_epoch, limit_tokens, remaining_tokens). Map OpenAI headers 1:1, and for Anthropic set token fields to None and convert reset to absolute epoch by adding time.time(). This keeps retry logic uniform.

High-throughput batch jobs. Prefer OpenAI’s visibility if token volume varies wildly; Anthropic’s request-only view forces you into reactive backoff. If you must use Anthropic, pre-shard batches by estimated tokens and run a slow outer loop.

Latency-sensitive serving. Either works if you implement proactive throttling. But the rate limit headers openai anthropic differences mean you cannot share a single unmodified parser. Budget an afternoon for the adapter; it pays back in fewer 429s.

The headers are not just metadata—they are the control plane for your LLM traffic. Treat them as first-class inputs to your client architecture.

Tagsrate-limitsopenaianthropicheaders

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All rate limits, retries & error handling posts →