Skip to content

Rate limits are a design input, not an error

Most teams discover rate limits by hitting them in production. Reading them first turns a class of incidents into a scheduling decision.

Rate limiting tends to be treated as an obstacle. It is more useful to treat it as a published statement about how much concurrency a system will accept, which is information you want before you design a batch job, not after.

Four dimensions, not one

Ureh applies limits across four independent dimensions: per IP address, per API key, per client, and per endpoint. A request must pass all of them. That structure matters more than any individual number.

It means a noisy job running under one API key cannot exhaust the budget of another key on the same account. It also means moving your workload to more servers does not multiply your allowance, because the per client dimension follows the account rather than the origin. Teams occasionally discover this when horizontal scaling fails to increase throughput, and the fix is scheduling, not more machines.

Read the response, not the clock

When a limit is hit, the response tells you how long to wait. Use that value. Guessing produces a retry storm: every blocked client waits the same guessed interval and returns simultaneously, which reproduces the original spike exactly.

Add jitter on top of the advertised wait so a fleet of workers spreads out rather than synchronising. This is a small change that turns a repeating incident into a non event.

Shape the work, do not just throttle it

The most effective response to a rate limit is usually not slower retries but different batching. A nightly job that fires ten thousand purchases in ninety seconds and then idles for the rest of the day is a spike by construction. The same work spread across ten minutes fits comfortably inside any reasonable limit and finishes at the same wall clock time, because the retries it avoids were costing more than the pacing does.

Queue the work, drain the queue at a fixed rate, and let the queue absorb the burstiness. This is also what makes the job resumable when something fails halfway, which is a second benefit you get for free.

Fail open is a deliberate choice

One detail worth knowing: our rate limiter fails open. If the counter store is unreachable, requests are allowed rather than blocked. That is a considered trade off. Rate limiting protects against volume, and letting a transient infrastructure blip block every legitimate purchase would cause more harm than the abuse it guards against.

Security controls that must not fail open are handled separately and do fail closed. Knowing which is which tells you what to expect during a partial outage, and that is usually the information you want at three in the morning.

Building against the Ureh API?

The reference documents every endpoint, request and response shape.

Get API keys API reference

Related Articles

Payments

Why wallets debit before they settle

Debiting a wallet before the upstream provider confirms looks backwards until you think about what happens when two purchases arrive at once.