Design safe API throttling with our rate limit calculator. Model request windows, concurrency, bursts, and queue sizing to prevent 429 errors.
An API tells you “60,000 requests per minute”. You have twelve workers, a steady load, and occasional bursts, and you need to know three things: what each worker is allowed to do, how many milliseconds it should sleep between calls, and whether the traffic you are about to send fits at all. This calculator does that conversion. Enter the provider's limit and window, how many clients share it, a safety buffer, and your expected steady and burst traffic; it returns a safe ceiling, a per-client allowance, a sleep interval, a utilisation percentage, and how long a burst takes to drain.
All arithmetic happens in your browser — nothing is uploaded and no request is made to any API. Every input is mirrored into the URL, so a link reproduces the whole scenario for a colleague or a ticket. The sliders are logarithmic, which is what makes a range from 60 to 1,000,000 requests usable with one drag.
raw per second = limit / window secondssafe per second = raw × (1 − buffer/100)per client per second = safe / client countsleep interval (ms) = 1000 / per client per secondutilisation = expected per second / safe per second × 100, where expected per second is your steady RPM divided by 60headroom = safe per second − expected per secondqueue growth per minute = max(0, expected − safe) × 60burst backlog = max(0, burst size − safe per second × burst window)burst recovery = backlog / headroom, and undefined when there is no headroom to drain it withPer-minute and per-hour figures are the per-second figure multiplied by 60 and 3600 — the tool does not model diurnal shape, so an hourly number here means “this rate sustained for an hour”, not “your traffic over the next hour”.
Set limit to 5,000, window to 3,600 seconds, clients to 4, buffer to 20%. Raw capacity is 5,000 / 3,600 = 1.389 requests per second. The buffer takes it to 1.111 per second as the safe ceiling. Split across four workers, each gets 0.278 requests per second — about 17 per minute — and a sleep interval of 3,600 ms between calls. That last number is the one to put in the code.
Now add traffic. If steady load is 30 requests per minute, expected is 0.5 per second, utilisation is 45%, and headroom is 0.611 per second. Give it a burst of 500 requests arriving over 10 seconds: the array can only absorb 1.111 × 10 = 11.1 of them inside the window, so the backlog is 488.9 requests. Draining that at 0.611 per second takes 800 seconds — 13 minutes and 20 seconds of queue before you are level again. A burst four hundred times the size of a per-second allowance is not a spike your throttle absorbs; it is a spike your queue absorbs, and the calculator tells you how long the tail is.
The default preset is worth understanding too, because it is deliberately uncomfortable: 60,000 per minute, 20% buffer, 12 clients, and 48,000 expected RPM. Raw is 1,000/s, safe is 800/s, and expected is also exactly 800/s — utilisation lands on 100%, the reading turns red, and headroom is zero. It is a picture of a system with no room for anything to go wrong.
The buffer defaults to 20% and ranges from 0 to 90%. Running at the published limit fails for reasons that have nothing to do with your arithmetic:
The client count field exists for the same reason. If twelve workers each independently implement “the documented limit”, you will send twelve times the documented limit. Dividing the budget explicitly is the fix, and it is why the per-client figure is the headline output rather than the array-wide one.
| Algorithm | How it behaves | Burst handling | Main weakness |
|---|---|---|---|
| Fixed window | A counter per calendar window, reset at the boundary | Allows a full window's traffic on each side of a boundary | Up to double the intended rate across a boundary; trivial to implement, which is why it is everywhere |
| Sliding window log | Timestamps every request and counts the last N seconds | Exact | Memory grows with request volume per key |
| Sliding window counter | Weights the previous window's count by how far into the current one you are | Close to exact | An approximation; slightly wrong for very uneven traffic |
| Token bucket | Tokens refill at a constant rate up to a capacity; each request spends one | Absorbs a burst up to the bucket capacity, then falls back to the refill rate | You must choose capacity and refill separately — two knobs, not one |
| Leaky bucket | Requests queue and drain at a fixed rate | Smooths bursts into a steady output instead of passing them through | Adds latency; the queue can grow unboundedly if you do not cap it |
The distinction that matters in practice is burst versus sustained. Token bucket separates the two explicitly: capacity is your burst allowance, refill rate is your sustained allowance. Leaky bucket refuses to pass bursts through at all — which is what you want when the thing downstream is fragile, and wrong when latency is what users notice. Fixed windows conflate both and are the reason a service that “allows 100 per minute” can be hit with 200 requests in two seconds.
The tool's Token Bucket Blueprint panel converts your inputs directly into implementation parameters: capacity set to the provider's per-window limit, refill rate set to the safe per-second figure, a per-client token allowance, and the sleep interval. Those four values are enough to configure most bucket implementations.
The calculator's job ends at choosing numbers; here is what happens when a request goes over, because it shapes how you should handle the ones the budget does not cover.
RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset are increasingly common, alongside older vendor-prefixed variants like X-RateLimit-*. When present they let a client throttle adaptively from what the server reports rather than from a number in documentation that may be out of date.A well-behaved client therefore does three things at once: paces itself with a sleep interval derived from its share of the budget, backs off on 429 with jitter, and adjusts its pace when the response headers say the budget is tighter than it assumed.
Beyond the headline numbers, the tool derives a few figures worth watching:
It assumes one limit with one window. Real providers frequently stack several — per second, per minute, per day, per endpoint, per organisation and per key — and the binding constraint may not be the one in the headline. Run the calculator once per limit and take the tightest per-client result. It also assumes requests are uniform; if some calls cost more quota than others, or the provider prices in tokens or compute units rather than requests, convert to the provider's unit before entering a limit. And it models a steady rate, not a shape: a job that fires everything at the top of the hour needs the burst fields, not the steady RPM field.
Rate limiting is a critical technique for controlling the number of requests a client can make to an API within a specified time window. It protects your infrastructure from overload, prevents abuse, ensures fair resource allocation, and maintains service quality for all users.
Infrastructure Protection: Without rate limits, a single client or malicious actor could overwhelm your servers with requests, causing degraded performance or complete outages for all users. Rate limiting acts as a circuit breaker that prevents cascading failures.
Cost Control: Cloud providers charge based on compute time, bandwidth, and API calls to downstream services. Uncontrolled request volumes can lead to unexpected bills running into thousands of dollars. Rate limiting caps your maximum exposure.
Fair Resource Allocation: In multi-tenant systems, rate limits ensure that no single customer monopolizes shared resources. A noisy neighbor shouldn't be able to slow down everyone else's experience.
DDoS Mitigation: While not a complete defense, rate limiting is your first line of protection against denial-of-service attacks. It forces attackers to distribute their requests across more IP addresses and time.
Compliance and SLA Management: Many third-party APIs impose strict rate limits. Your internal rate limiting must stay within those bounds to avoid service interruptions and maintain contractual obligations.
The token bucket algorithm is the most flexible and widely-used approach. Imagine a bucket that holds tokens, with new tokens added at a fixed rate. Each request consumes one token. If the bucket is empty, requests must wait or be rejected.
How it works:
Advantages:
Use cases: API gateways, microservices communication, client SDKs
The leaky bucket enforces a strictly constant output rate, regardless of input spikes. Requests enter a queue (bucket) and are processed at a fixed rate. If the queue fills up, new requests are rejected.
How it works:
Advantages:
Disadvantages:
Use cases: Traffic shaping, streaming data pipelines, telecom systems
The fixed window algorithm counts requests in fixed time windows (e.g., per minute) and rejects requests once the limit is reached.
How it works:
Advantages:
Disadvantages:
Use cases: Simple APIs, prototyping, systems where boundary spikes aren't a concern
Sliding window log maintains a log of request timestamps and counts requests in a sliding time window, providing more accurate rate limiting than fixed windows.
How it works:
Advantages:
Disadvantages:
Use cases: High-security APIs, premium tiers, systems requiring precise fairness
A hybrid approach that combines fixed window efficiency with sliding window accuracy. It uses weighted counters from the current and previous windows.
How it works:
previous_window_count × overlap_percentage + current_window_countAdvantages:
Disadvantages:
Use cases: Production APIs, rate limiting middleware, modern API gateways
For public APIs: Use token bucket for flexibility and burst handling For background workers: Use leaky bucket for consistent throughput For simple use cases: Start with fixed window for quick implementation For critical systems: Consider sliding window log for maximum accuracy
When running multiple servers, you need a centralized state store:
Redis-based Implementation:
import redis
import time
redis_client = redis.Redis(host='localhost', port=6379)
def is_rate_limited(user_id, limit=100, window=60):
key = f"rate_limit:{user_id}"
current = int(time.time())
# Remove old entries outside the window
redis_client.zremrangebyscore(key, 0, current - window)
# Count requests in current window
request_count = redis_client.zcard(key)
if request_count < limit:
# Add current request
redis_client.zadd(key, {current: current})
redis_client.expire(key, window)
return False
return True
Token Bucket with Redis:
def check_rate_limit_token_bucket(user_id, capacity=1000, refill_rate=100):
key = f"token_bucket:{user_id}"
now = time.time()
# Get current state
data = redis_client.hgetall(key)
if not data:
# Initialize bucket
tokens = capacity - 1
last_refill = now
else:
tokens = float(data[b'tokens'])
last_refill = float(data[b'last_refill'])
# Calculate tokens to add
elapsed = now - last_refill
tokens_to_add = elapsed * refill_rate
tokens = min(capacity, tokens + tokens_to_add)
if tokens < 1:
return True # Rate limited
tokens -= 1
# Update state
redis_client.hset(key, mapping={
'tokens': tokens,
'last_refill': now
})
redis_client.expire(key, 60)
return False
Always include rate limit information in response headers:
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4987
X-RateLimit-Reset: 1699564800
Retry-After: 13
This helps clients implement proper backoff strategies.
Different user tiers should have different limits:
Consider implementing burst limits separately from sustained limits.
Don't just reject requests with 429 errors. Consider:
Apply limits at multiple levels:
Track these metrics:
Alert when:
Your API documentation must include:
Don't rely solely on server enforcement. SDKs should:
When multiple servers have different system times, rate limiting becomes inconsistent. Solutions:
When rate limit windows reset, all clients may rush to send requests simultaneously. Mitigations:
If your token bucket capacity is too small, legitimate traffic spikes get rejected. Guidelines:
Generic "Too Many Requests" errors frustrate developers. Include:
When clients automatically retry failed requests, you can enter a death spiral where retries consume all capacity. Solutions:
Stripe uses a token bucket algorithm with:
GitHub implements multiple tiers of rate limiting:
Twitter uses sliding window rate limiting:
Always test your rate limiting implementation:
# Burst test - send 1000 requests as fast as possible
for i in {1..1000}; do
curl -s -o /dev/null -w "%{http_code}\\n" https://api.example.com/endpoint
done | sort | uniq -c
# Sustained load test
wrk -t12 -c400 -d30s --latency https://api.example.com/endpoint
# Verify headers
curl -i https://api.example.com/endpoint | grep -i rate
Look for:
Rate limiting is not just about preventing abuse—it's about building resilient, scalable systems that provide predictable performance for all users. By choosing the right algorithm, implementing it correctly across distributed systems, and following best practices, you create an API that's both developer-friendly and operationally sound.
Remember: rate limiting is not a replacement for proper capacity planning, auto-scaling, or architectural optimizations. It's one layer in a defense-in-depth strategy for building production-ready APIs.
Start with 10-20% below the published limit. This cushion absorbs clock drift between systems, network jitter, and uneven worker performance while leaving room for retries. Increase the buffer if you operate in multiple regions or cannot centrally coordinate concurrency.
The raw limit reflects the provider's documented request ceiling. The safe limit applies your safety buffer, giving you a conservative budget for steady-state traffic. Staying within the safe numbers avoids spiky traffic that triggers rate-limit bans.
Short bursts can exceed per-second throughput while still staying inside the long-term window. A queue absorbs these bursts so workers can drain them at a compliant pace. Without a queue, overlapping bursts can produce immediate 429 responses.
Use the token bucket values to throttle each worker. Refill tokens at the safe per-second rate, and require one token per request. When workers run out of tokens, they wait based on the suggested delay or implement exponential backoff. Log every 429 response and feed it back into this calculator to update your inputs.