Rate Limiting Is a Product Decision, Not Just a Security Control

Key takeaway: Rate limits are a contract between an API provider and its clients, and setting them well requires understanding the actual usage patterns of your clients rather than picking a number that feels safe, because a limit that is too low breaks legitimate integrations and one that is too high lets a single client harm everyone else.
What Rate Limits Are Actually For
Rate limiting protects the API and its underlying infrastructure from being overwhelmed by a single client or a burst of traffic, whether accidental or malicious, and it also communicates expectations to clients about how much they can reasonably depend on the API. A well-designed limit keeps the service healthy for everyone while giving legitimate clients enough headroom to do what they need.
The tension is that these two goals pull in opposite directions — protecting the service argues for lower limits, while supporting legitimate clients argues for higher ones — and the right balance depends entirely on the specific API and its clients, which is why a limit that is perfect for one API can be completely wrong for another.
The Common Failure Modes
| Failure mode | Consequence |
|---|---|
| Limit too low | Legitimate clients hit the ceiling and break |
| Limit too high | A single client can degrade the service for everyone |
| No differentiation between client tiers | Power users and casual users treated identically |
| Limits not communicated clearly | Clients cannot design around them |
A limit set too low is the more common and more damaging failure in practice, because it breaks real integrations that were working — a client that was fine for months suddenly starts failing once it grows, and the failure is entirely the provider’s choice of limit, not anything the client did wrong. This is why limits should be set based on observed real usage patterns rather than an arbitrary number.
Designing Limits That Work
Differentiating limits by client tier — a higher limit for paying or trusted clients, a lower one for free or untrusted ones — is usually the right structure, because it lets the provider protect the service while giving its most important clients the headroom they need, and it gives clients a clear incentive and path to a higher tier.
Communicating limits clearly is as important as setting them — clients need to know what the limit is, how much of it they have used, and when it resets, which is why the standard practice is to return this information in response headers on every request, so clients can design their own behaviour around the limits rather than discovering them by failing.
Handling the Over-Limit Response Well
When a client exceeds its limit, the response should be explicit and informative — a clear status code indicating the request was rate limited, information about when the limit resets, and ideally a Retry-After header telling the client when it can try again — rather than a generic error that gives the client no way to understand what happened or when to retry, which turns a recoverable situation into a confusing one.
The Bottom Line
Set rate limits based on observed real usage patterns rather than arbitrary numbers, differentiate limits by client tier so you can protect the service while supporting your most important clients, and communicate limits clearly in response headers so clients can design around them. Handle over-limit requests with an explicit, informative response that tells the client when it can retry, rather than a generic error.



