q=qequals

API rate limit 429: per-user limits for a shared key

What a 429 means, what the rate-limit headers tell you, and the containment checklist that stops one client or one looping agent from spending a shared API budget.

Qqequals·Oct 9, 2026·6 min read

A 429 is normal. It means a client has sent too many requests in a given amount of time, a condition called rate limiting, and MDN's reference notes the status code is defined in RFC 6585 as a standard protective measure. What isn't normal is one client, one prompt or one looping agent spending a budget meant for hundreds of servers. If you share vendor access across an agent harness, per-user containment is the feature to build first.

What a 429 Actually Tells You

HTTP 429 Too Many Requests means the server wants the client to slow down. Rate limits protect a service from crashing under a flood of traffic, from malicious bursts, and from one heavy user crowding out everyone else, and they keep infrastructure costs predictable.

Limiters identify the caller in one of three ways, according to MDN's reference:

  • By API key or access token, tied to a registered user or organization account.
  • By IP address, for requests from the same machine or network.
  • By endpoint, for traffic into a single demanding resource.

Requests that carry authentication or cookies can be limited per user or per application. That is the hook a shared harness needs: if the vendor limits your whole key, you have to add the per-user layer yourself.

Servers tell you where you stand through headers. RateLimit-Limit or RateLimit-Policy gives the maximum volume, RateLimit-Remaining the requests left in the current window, and RateLimit-Reset the seconds until it refills. A 429 response carries Retry-After, the number of seconds to wait before trying again.

Bird's explainer on handling 429s shows what those headers look like in practice. A policy header such as "email_send";q=1000;w=60 allows 1,000 requests per 60-second window, and a companion header with r=842;t=35 says 842 requests remain with 35 seconds to reset. Bird adds that the numbers illustrate the format and aren't a promised quota: read the values your client actually receives, and account for every policy a response carries.

The Shared-Harness Problem: One Client Uses It All

One operator describes the setup plainly. They want to share their DataForSEO, fal and other API access with hundreds of servers running their agent harness, from day one, so every client can use some of it. The ask that follows is rate limits, "per user limit on tool call so one client does not use it all," plus toolkit scoping, so one group gets one set of tools and another group a different set, with some overlap where integrations connect.

Without that scoping, every member draws on the same toolkit and the same budget. One runaway prompt, one looping agent or one heavy client, and the shared balance is gone before the rest of the fleet gets a turn.

The cost version of the same failure appears in another reply: "make sure to configure custom limits for the credits usage. my agent churned through the 129 sub in 5 mins." The per-call price wasn't the problem. Nothing stopped the loop, which is the case for spending limits and a cache on agent calls on top of rate limits.

Adding keys doesn't fix it either. Bird's explainer is explicit that its send limits apply across an organization, so separate keys don't create separate budgets, and creating more keys doesn't raise an organization-wide limit. Other vendors scope limits differently, so read their documentation, but assume the shared pool is shared until a vendor says otherwise.

Containment Checklist Before the Next Run

Do these in order. Each one narrows the damage the next one has to absorb.

1. Give every tenant its own bucket. Put a per-tenant token bucket in your own gateway, in front of the vendor key. A token bucket fills at a steady rate and every request spends a token: short bursts pass once tokens have built up, and sustained overuse waits instead of draining the shared pool. Size the bucket per user or client, not per key. The shared key is the pool; the per-tenant bucket is the bulkhead.

2. Scope toolkits per group. Expose only the tools each group needs, with overlap only where an integration genuinely serves both. If the platform gives every member every tool, add the check at your gateway: confirm group membership before the call reaches the vendor, and reject or queue out-of-scope calls locally.

3. Read Retry-After, then back off with jitter. On a 429, wait the seconds the header states. If the limit hits again, double the wait, 1s, then 2s, then 4s, then 8s, with a cap so retries can't stretch forever. Add a small random delay, called jitter, to each retry, so a fleet blocked at the same moment doesn't retry in lockstep and trip the limit again as one wave. Bird adds two details worth copying: match on the error's type or code rather than its message, which can change without the recovery changing, and keep the same idempotency key when you repeat the same write, a key that lets the server recognize a retry and avoid doing the work twice.

4. Coordinate workers that share a budget. One worker's last response can't account for requests other workers have sent since, Bird's explainer notes, so treat the remaining-quota headers as shared state across the fleet. Its own SDKs retry on 429 and honor Retry-After but don't coordinate a shared queue across processes. That part is yours to build.

5. Batch and cache before you spend. Group operations and keep static data locally instead of making the same call again. For search data that means checking your own cached copy for a keyword and location before any request goes out, and removing duplicates from a list before firing the batch. qequals meters every key by quota and counts cache hits against it, so the cache that saves budget there is your own.

6. Pick limiter math that fits tenants. A fixed window resets at clock intervals: simple, but spiky at the top of each minute. A sliding window looks back over a rolling timeframe: smoother, but heavier to track. A token bucket refills at a steady rate and allows brief bursts. For per-tenant containment, the token bucket absorbs one tenant's legitimate burst without letting it become everyone's new baseline.

What Not to Build

Don't build limit evasion. Rotating keys to dodge a shared ceiling, replaying rejected requests without waiting, or stripping identity headers to look like a new caller turns a protective measure into a terms violation and a reliability risk. Bird's advice runs the other way: if the quota stays too low for the workload, ask the vendor for an override.

Pacing reduces 429s without eliminating them. Bird notes that remaining requests can be spent by other workers between your checks, so keep the retry path even when everything is paced.

Before the next run, list every client that shares your vendor keys and give each one a ceiling. If one of them spikes tomorrow, only its own bucket should empty.