OpenAI rate limits: what the 429s mean and how to catch them in your logs

By Sazabi Team

Failure facts checked on the vendor’s docs on Nov 8, 2026.

An OpenAI 429 is a family of errors, not one error. The status code is the same for a burst of requests, a ramp that was too steep and a spend cap that stopped your account. The fix for each is different, so your logs need to tell them apart.

What OpenAI limits

OpenAI's rate limit guide lists five measures: requests per minute (RPM), requests per day (RPD), tokens per minute (TPM), tokens per day (TPD) and images per minute (IPM). You hit a limit when the first of them runs out. Twenty tiny requests can use up an RPM limit of 20 while you are nowhere near your token limit.

Limits belong to your organization and your project, not to a user or an API key. They differ by model, and some model families share one limit that you can see in the console's limits page. Your tier moves up automatically as total credit purchases reach each threshold (Build at $5, Launch at $100, Grow at $500). Batch API jobs have their own queue limit, counted in queued input tokens.

One detail catches teams out: the token estimate for a request uses the larger of max_tokens and an estimate from the request's character count. A large max_tokens on a small prompt spends limit you never use.

The three kinds of 429

What you seeWhat it meansRetry?
rate_limit_error with a request or token messageYou passed RPM, TPM or another temporary limitYes, after Retry-After
rate_limit_error with code slow_downTraffic grew too fastYes, at a lower rate, then ramp slowly
Code such as credit_balance_exhausted or organization_spend_limit_exceededMoney or approved usage ran outNo. See OpenAI quota exhausted

Model overload is a separate 503 with code server_is_overloaded. OpenAI notes that slow_down used to come back as a 503 on some endpoints and now returns 429, so an error handler written before that change may classify it wrong.

Headers worth logging

Each response can carry x-ratelimit-limit-requests, x-ratelimit-remaining-requests, x-ratelimit-reset-requests and the same three for tokens. The reset values are durations such as 1s or 6m0s. When a project-scoped token limit applies you also get x-ratelimit-*-project-tokens. A temporary 429 can include Retry-After, which OpenAI describes as the minimum wait.

Log the remaining values on every call, not only on failures. A remaining-tokens value that trends toward zero tells you about a 429 before it happens.

// Log one structured line per attempt, with rate limit headers.
async function errorCode(res: Response) {
  // Gateways can answer with HTML or an empty body; keep the log line either way.
  try {
    return (await res.clone().json()).error?.code ?? null
  } catch {
    return null
  }
}

async function callOpenAI(body: unknown, attempt: number) {
  const started = Date.now()
  const res = await fetch('https://api.openai.com/v1/responses', {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  })
  const h = res.headers
  console.log(
    JSON.stringify({
      msg: 'vendor call',
      vendor: 'openai',
      status: res.status,
      attempt,
      duration_ms: Date.now() - started,
      remaining_requests: h.get('x-ratelimit-remaining-requests'),
      remaining_tokens: h.get('x-ratelimit-remaining-tokens'),
      reset_tokens: h.get('x-ratelimit-reset-tokens'),
      retry_after: h.get('retry-after'),
      request_id: h.get('x-request-id'),
      error_code: res.ok ? null : await errorCode(res),
    })
  )
  return res
}

What to alert on

  • The share of calls answered 429 per model over five minutes. A handful of 429s that clear on retry is normal for a busy account. A share well above the model's usual level, held for several minutes, is not.
  • error_code counts. slow_down after a deploy or a batch job start points at your ramp. A spend or credit code is an account problem that needs a person.
  • Remaining tokens under 10% of the limit for a sustained period.
  • Attempts per successful call. Retries that pile up mean your backoff is not working.

Your bug or their limit

If only one model or one project 429s, the limit is yours: look at what changed in that code path. If many models fail with 503 and server_is_overloaded, that is OpenAI capacity, not your quota, and retrying with delay is the documented response. Check that SDK retries and your own retries are not both active. OpenAI warns that nested loops multiply requests, and its examples set max_retries=0 before adding their own wrapper.

Example: a ramp that was too steep

This is an example, not output from a real project. A nightly job at a made-up service called summarizer-worker raises its concurrency from 4 to 40 at 02

.

02:00:03Z msg="vendor call" vendor=openai model=gpt-example status=200 attempt=1 remaining_tokens=412000 retry_after=
02:00:41Z msg="vendor call" vendor=openai model=gpt-example status=429 attempt=1 error_code=slow_down remaining_tokens=388000 retry_after=3
02:00:44Z msg="vendor call" vendor=openai model=gpt-example status=429 attempt=2 error_code=slow_down remaining_tokens=391000 retry_after=3
02:00:49Z msg="vendor call" vendor=openai model=gpt-example status=200 attempt=3 remaining_tokens=402000 retry_after=

Remaining tokens are healthy the whole time, which rules out a TPM limit. The slow_down code and the 02

start point at the concurrency jump. The fix is to ramp the job in steps, not to ask for a higher limit.

Checklist

  1. Log status, error_code, remaining requests and tokens, and retry_after on every attempt.
  2. Cap attempts and total retry time, and honor Retry-After plus jitter.
  3. Ramp new traffic in steps instead of starting at full rate.
  4. Set max_tokens close to the output you expect.
  5. Send work that can wait to the Batch API.
  6. Treat spend and credit codes as non-retryable.

For the general approach, see monitoring third-party dependencies and vendor degradation. If you track the cost side of model calls, LLM spend spikes covers it. Structured fields like these are easiest to query when your logs are structured. If these lines already reach Sazabi, the agent can watch the 429 share for you.

OpenAI rate limits facts

  • Several limits, first one wins: OpenAI measures requests per minute, requests per day, tokens per minute, tokens per day and images per minute, and you can hit any of them first. (OpenAI docs, accessed Nov 8, 2026)
  • Limits are per organization and project: Limits are defined at the organization and project level, not per user, and vary by model, with some model families sharing one limit. (OpenAI docs, accessed Nov 8, 2026)
  • Response headers: Responses carry x-ratelimit-limit, remaining and reset headers for requests and tokens, and Retry-After on temporary 429 and 503 responses when present. (OpenAI docs, accessed Nov 8, 2026)
  • slow_down is a ramp-rate error: A 429 with code slow_down means traffic grew too fast, even when you are inside your RPM and TPM limits. (OpenAI docs, accessed Nov 8, 2026)
  • Retries need a cap: Official SDKs retry eligible 429 and 503 responses, and OpenAI says to limit attempts and total retry time so nested retry loops do not multiply requests. (OpenAI docs, accessed Nov 8, 2026)

With Sazabi

The Sazabi agent automatically sets up sensors for your project and maintains them over time. When your code calls OpenAI, it watches a question like this one:

Tell me when the share of OpenAI calls answered with a 429 is well above its usual level, per model.

When the answer turns abnormal, Sazabi investigates and opens an issue. Vendor rate limiting covers the signal behind it.

Frequently Asked Questions

What does an OpenAI 429 mean?

It can mean three different things: you passed a temporary rate limit, your traffic ramped up too quickly (slow_down), or you hit a billing or spend limit. Read error.code before you decide whether to retry.

Should I retry an OpenAI 429?

Retry a temporary rate limit, waiting at least the Retry-After value when it is present, and add jitter. Do not retry credit or spend-limit errors: OpenAI says retrying them will not restore access.

Why do I get 429s when I am under my limits?

A slow_down error reflects how fast your traffic grew, not whether you used up RPM or TPM. OpenAI suggests raising traffic by no more than 50% every 15 minutes once you reach 1 million input tokens per minute.

Do failed requests count against my limit?

Yes. OpenAI says unsuccessful requests contribute to the per-minute limit, so resending in a tight loop makes throttling worse.

Sources

  1. Limit dimensions, usage tiers, x-ratelimit headers, slow_down and server_is_overloaded errors, ramp guidance and retry guidance (accessed Nov 8, 2026)
  2. The 429 variants, including rate limit, slow_down and the spend and credit codes that retries do not fix (accessed Nov 8, 2026)
  3. Hard spend limits return a 429 with organization_spend_limit_exceeded or project_spend_limit_exceeded (accessed Nov 8, 2026)