cd /news/developer-tools/api-429-errors-rate-limits-retry-aft… · home topics developer-tools article
[ARTICLE · art-104650] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

API 429 Errors: Rate Limits, Retry-After, and Safe Retries

A developer explains how to handle API 429 rate-limit errors, emphasizing the need to read response headers and bodies, identify the specific limit, and implement bounded retries with jitter. The post highlights that 429 responses vary by provider and scope, and advises against blindly retrying without understanding the cause. It also references OpenAI's error codes and BetterToken's API documentation as examples.

read4 min views1 publishedAug 20, 2026

An API 429 error means the server rejected a request because of a rate or usage limit. Read the response body and headers first, identify the limit, and allow only a bounded retry. For operations with side effects, determine whether the first request completed before sending another one.

RFC 6585 defines 429 as "too many requests in some period." The response may contain Retry-After

, but the standard does not specify a single way of counting: the server can limit a single resource, a key, a project, an organization, or an entire cluster.

Therefore, status 429 in itself does not answer the question “how long to wait.” For one API, this is a short-term RPM or TPM limit; for another, it is an exhausted balance, a monthly quota, or a set spending limit. For example, in the current OpenAI error table different reasons 429 have different codes: temporary exceeding the rate limit, exhausted credit and project or organization limits. They cannot be repeated by one handler.

Symptom What to check Response Data Safe Action
429 appeared after a surge in parallel requests Competitiveness and a short limit window
Retry-After , error fields, rate-limit headers
Reduce concurrency, wait for specified time, then send one probe
429 occurs on large requests Limit of tokens for the period Usage of previous queries, input size and max_tokens
Reduce packet or output, distribute load
429 returned on every request Quota, balance, spend limit or project blocking Machine readable code and payment/limit message
Stop retry and eliminate the cause in the provider's account
429 occurs only for some keys or projects Scope of the limit Project/org ID, key, current tier Match the request to the correct project and its limits
After retry the number 429 grows Retry storm Number of attempts, concurrency, queue Stop the wave of replays, add jitter and overall time limit
The answer is actually 401 or 403 Authentication or rights HTTP status and error type Do not repeat as 429; fix key, rights or regional restriction

If 429 occurs in a request via BetterToken, current API documentation and Dashboard provide an additional verification point: there you can compare the time, model, status, input/output/cache tokens and consumption of your own request. This data helps restore the load profile, but does not prove the cause of 429 with another provider; for this we need his answer and documentation.

First save the full HTTP status, error body and headers without the API Key. If a valid Retry-After

is present, consider it the minimum delay. Add a small random jitter to prevent multiple workers from waking up at the same time.

If there is no header or it is not parsed, use an exponential delay with jitter and a hard limit on the number of attempts and total time. OpenAI recommendations on rate limits specifically warn that unsuccessful requests can also be counted towards the minute limit: frequent repetitions can only prolong the problem.

Do not transfer specific header names between providers. First, check the current contract of the required API: the set of fields, time units and the scope of the limit may differ.

The following is pseudocode, not a finished library. Choose delays and attempt limits for the specific operation and the provider's documentation.

function send_with_retry(request, max_attempts, total_deadline):
    attempt = 0
    started_at = now()

    while attempt < max_attempts and now() < total_deadline:
        response = send(request)

        if response.status != 429:
            return response

        error = parse_error(response.body)
        if error means quota, balance, spend limit or manual action:
            stop without retry

        if response has valid Retry-After:
            base_wait = parse_retry_after(response)
        else:
            base_wait = exponential_delay(attempt)

        sleep(base_wait + random_jitter())
        attempt += 1

    raise RetryBudgetExhausted

Before adding your own loop, check if the SDK does automatic retries. Otherwise, one “application replay” can turn into several hidden HTTP requests.

Repeating a status or list read is usually safer because it doesn't have to create a new object. But POST

, which sends a message, debits money, starts a task, or creates a record, may be executed before the client receives a response.

This operation requires one of three mechanisms:

You can’t add an idempotency key “for show”: first check that a specific endpoint actually supports it and how long it stores the result.

After the limit window ends, do not return all traffic at once.

If the probe gets a 429 again with a quota or balance message, waiting won't solve the problem. If 429 only appears when concurrency increases, limit queuing and concurrency rather than increasing retries.

The safe order is: save the response → define type 429 → perform the required action or withstand Retry-After

→ use limited backoff with jitter → test one request → eliminate duplicate side effect. Infinite retry and a generic handler for 401, 403, 429 and timeout hide the reason and create a new load.

Originally published on the BetterToken blog.

BetterToken provides pay-as-you-go access to AI model APIs through

OpenAI-compatible and Anthropic-compatible endpoints — useful if you are wiring

Claude Code, Codex, or your own tooling to a custom base URL.

See the docs to get started.

── more in #developer-tools 4 stories · sorted by recency
── more on @openai 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/api-429-errors-rate-…] indexed:0 read:4min 2026-08-20 ·