API Rate Limiting: Algorithms and Best Practices
API rate limiting is not just a defense against attackers. It is how you keep a busy integration stable when a customer imports a large file, a retry loop goes wrong, or one tenant suddenly sends half your traffic. This guide explains the main rate-limiting algorithms, shows how to set useful limits, and covers the server and client behavior that prevents a routine traffic spike from becoming an outage.
The short version
Start with a token bucket tied to an authenticated account or API key. Return HTTP 429 with Retry-After, publish the limit clearly, and make clients back off with jitter. Set separate limits for cheap reads, expensive writes, and sensitive actions instead of forcing every endpoint into one blunt quota.
What API rate limiting actually controls
A rate limiter measures requests against a rule, such as 120 requests per minute for one API key. Requests inside the allowance proceed. Requests beyond it wait, fail, or enter a queue. That simple gate protects your database, third-party services, worker pool, and every other customer sharing the system.
Rate limiting is different from concurrency control. A rate limit controls how much traffic arrives over time. A concurrency limit controls how many requests run at once. Mature APIs often need both. For example, an export endpoint might allow a reasonable number of jobs per hour but only one active export per account.
This matters in customer-facing automation too. Intellure connects messaging, lead follow-up, and booking systems behind one managed AI employee. Those integrations need limits that absorb a campaign-driven message burst without delaying normal customer conversations.
Choose the right rate-limiting algorithm
The algorithm decides whether bursts are allowed, how accurately traffic is measured, and how much state your system must store. There is no universal winner, but there is usually a clear fit for each workload.
| Algorithm | Best use | Main strength | Main tradeoff |
|---|---|---|---|
| Fixed window | Simple internal APIs | Easy and inexpensive | Boundary bursts can double traffic |
| Sliding log | Strict, low-volume limits | Very accurate | Stores each request timestamp |
| Sliding window counter | General public APIs | Good accuracy with less state | Uses an estimated rolling count |
| Token bucket | APIs that allow short bursts | Flexible and widely understood | Needs atomic token updates |
| Leaky bucket | Work queues and steady processing | Smooth output rate | Can add latency during bursts |
For most product APIs, a token bucket is the practical default. Tokens refill at a steady rate, and each request spends one or more tokens. You can permit a brief burst without allowing that burst to continue indefinitely. If every request must be treated with strict rolling-window fairness, use a sliding window counter instead.
Set limits from capacity, cost, and user behavior
Do not copy a familiar requests-per-minute number from another API. Start with measured capacity. Load test the endpoint, find the throughput where latency or error rates begin to rise, and keep normal traffic well below that point. Reserve capacity for retries, internal jobs, and unexpected peaks.
Then look at real user behavior. A limit should stop abuse without breaking ordinary work. Measure the high end of legitimate usage, not just the average. If one customer can reasonably upload 500 records in a batch, a limit designed around manual clicks will fail the first real integration.
Group endpoints by cost
A cached lookup and a report that scans millions of rows should not spend the same allowance. Assign weighted tokens or separate buckets to reads, writes, search, exports, and AI-powered operations.
Limit by a stable identity
Prefer account, tenant, user, or API key. Add IP-based limits for sign-in, password reset, and other unauthenticated routes, but do not make IP address the only identity for authenticated customers.
Separate burst and sustained rates
Let a dashboard load several resources at once, then enforce a lower steady refill rate. This preserves a responsive user experience while preventing continuous high-volume traffic.
Keep an emergency margin
Do not allocate every unit of tested capacity. Background work, failovers, and traffic shifts need room. A rate limiter should protect a healthy service, not hold it permanently at its breaking point.
Return a useful HTTP 429 response
When a client exceeds its allowance, return HTTP 429 Too Many Requests. Include Retry-After so the client knows when it may try again. Also expose the limit, remaining allowance, and reset time in consistent headers or structured response fields. Pick one convention, document it, and use it across every endpoint.
The response body should explain which limit was hit and what the client can do next. Avoid a generic server error. A clear error lets developers slow their queue, reduce batch size, or request a different usage tier without opening a support ticket.
Make retries safe on the client
Immediate retry loops turn a small overload into a larger one. A client should honor Retry-After first. If it is absent, use exponential backoff: wait longer after each failure, add random jitter so clients do not retry together, and stop after a defined number of attempts.
Retried writes also need idempotency. Accept an idempotency key for operations such as creating an order or booking an appointment. Store the first successful result and return it for repeated requests with the same key. This prevents a timeout followed by a retry from creating duplicate work.
Managed systems should own this complexity. For example, Intellure handles the integration layer for customer messages, follow-ups, and appointment booking, so a business does not have to build custom retry queues for WhatsApp, Instagram, and website conversations.
Implement rate limiting in a distributed system
A counter stored inside one application process fails as soon as traffic reaches another instance. Put shared state in a fast central store, or enforce the limit at an API gateway that sees every request. Updates must be atomic so simultaneous requests cannot all spend the same remaining token.
Decide what happens if the limiter itself is unavailable. Fail-open keeps the API reachable but removes protection. Fail-closed protects a sensitive operation but can cause a full outage. A useful compromise is endpoint-specific behavior: fail-open with a conservative local fallback for ordinary reads, and fail-closed for login attempts or costly writes.
Monitor the limiter, not just the API
Track allowed requests, rejected requests, retry volume, limiter latency, and the identities hitting limits most often. Break those metrics down by endpoint and customer tier. A growing 429 rate may reveal abuse, but it can also reveal a legitimate workflow that your original limits did not anticipate.
Alert on sudden changes rather than any single rejection. Review limit data when you release a feature, change infrastructure, or add a major integration. Intellure uses managed automation so these operational details stay behind the service while the business gets the outcome: customers answered, leads followed up, and appointments booked.
Common rate-limiting mistakes
The most common mistake is one global limit for every route and every customer. It is simple, but it ignores cost and breaks legitimate bursts. Other failures include trusting IP address as identity, returning 500 instead of 429, omitting Retry-After, and silently changing limits without updating documentation.
Also avoid using rate limiting as your only security control. It does not replace authentication, authorization, input validation, request size limits, timeouts, or abuse detection. It is one layer in a system that assumes clients and networks will sometimes behave badly.
Frequently asked questions
What is API rate limiting?+
What status code should a rate-limited API return?+
Which rate-limiting algorithm is best?+
Should rate limits apply by IP address or API key?+
How should clients handle HTTP 429 responses?+
The bottom line
Good API rate limiting is predictable for developers and almost invisible to users. Measure real capacity, give different work the limits it deserves, return clear 429 responses, and make retries safe. If your goal is reliable customer automation without owning that integration work, an Intellure AI employee provides the managed layer and keeps conversations moving around the clock.