Distributed Rate Limiting API
Distributed Rate Limiting checks and enforces per-user, per-IP, or per-tenant request quotas across your entire fleet — with three algorithms, atomic Redis-backed counters, and sub-millisecond response.
What is it?
Distributed Rate Limiting checks and enforces per-user, per-IP, or per-tenant request quotas across your entire fleet — with three algorithms, atomic Redis-backed counters, and sub-millisecond response. It accepts a single JSON payload and returns a structured response in milliseconds — no agents, plugins, or background workers required. The API is designed for synchronous, real-time use: call it inline in your request handler, CI step, or event pipeline and act on the result immediately.
Why do you need it?
Problem
- In-process rate limiting fails immediately when you run more than one server instance — each instance has its own counter, so users get N× their intended quota across N servers.
- Session-sticky load balancing can work around this, but breaks when servers restart, during deploys, and with any stateless architecture.
- Building distributed rate limiting yourself requires managing Redis, handling race conditions, implementing multiple algorithms, and dealing with Redis failover — weeks of work for a non-differentiating feature.
Consequence
- A user hitting 10 API servers with a 100 req/min limit effectively gets 1,000 req/min — 10× the intended quota. Paid tier abuse and DDoS attacks bypass your protection entirely.
- Runaway API clients without effective rate limiting can saturate your database connection pool, causing cascading failures that affect all users — not just the abusive client.
- Without token-bucket limiting on AI/LLM endpoints, a single user can exhaust your entire monthly API budget in hours — at current token costs, one bad actor can cost $10,000+ overnight.
Solution
- Centralized, atomic rate limit state shared across your entire fleet — add as many servers as you need without any rate limit drift.
- Three algorithms (fixed window, sliding window, token bucket) so you pick the right behavior for each use case rather than forcing one algorithm everywhere.
- Drop-in: one API call per request, works in any language, no Redis infrastructure to manage.
Use cases
API tier enforcement
Enforce free/paid quotas per API key using a sliding window algorithm, so free users can't burst past their monthly limit regardless of traffic patterns.
Node.js — tier enforcement middleware
const API_KEY = process.env.DEVOPSIL_API_KEY;
async function rateLimitMiddleware(req, res, next) {
const result = await fetch('https://devopsil.com/api/v1/ratelimit/increment', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `api_key:${req.apiKey}`,
algorithm: 'sliding_window',
limit: getUserLimit(req.apiKey), // e.g. 1000 for free, 10000 for pro
window_seconds: 3600, // per hour
}),
}).then(r => r.json());
res.set('X-RateLimit-Remaining', result.remaining);
if (!result.allowed) return res.status(429).json({ error: 'Rate limit exceeded' });
next();
}result.allowed is the boolean gate. result.remaining and result.reset_at populate standard rate limit headers for the client.
Login brute-force protection
Rate limit authentication attempts by IP address with a tight fixed window, automatically blocking brute-force attacks across your entire fleet.
Node.js — login rate limit
const API_KEY = process.env.DEVOPSIL_API_KEY;
async function checkLoginRateLimit(ipAddress: string) {
const result = await fetch('https://devopsil.com/api/v1/ratelimit/increment', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `login:${ipAddress}`,
algorithm: 'fixed_window',
limit: 10,
window_seconds: 300, // 10 attempts per 5 minutes
}),
}).then(r => r.json());
return result;
}Return 429 with Retry-After header when result.allowed is false. result.reset_at gives the exact timestamp when the window resets.
AI/LLM cost control
Rate limit token-expensive endpoints by user with the token bucket algorithm, allowing short bursts while enforcing a sustainable average token spend per user.
Node.js — LLM token rate limit
const API_KEY = process.env.DEVOPSIL_API_KEY;
async function checkLlmRateLimit(userId: string, estimatedTokens: number) {
const result = await fetch('https://devopsil.com/api/v1/ratelimit/increment', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `llm:${userId}`,
algorithm: 'token_bucket',
limit: 100000, // 100K tokens bucket capacity
refill_rate: 10000, // refill 10K tokens per minute
cost: estimatedTokens,
}),
}).then(r => r.json());
return result;
}result.allowed gates the LLM call. result.remaining shows available token capacity. Burst traffic is absorbed by the bucket; sustained abuse is blocked.
Webhook send-rate control
Rate limit outbound webhook dispatches per tenant to prevent a high-volume tenant from overwhelming your dispatch infrastructure.
Node.js — outbound webhook throttle
const API_KEY = process.env.DEVOPSIL_API_KEY;
async function canDispatchWebhook(tenantId: string) {
const result = await fetch('https://devopsil.com/api/v1/ratelimit/increment', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `webhook_dispatch:${tenantId}`,
algorithm: 'sliding_window',
limit: 500,
window_seconds: 60, // 500 dispatches per minute per tenant
}),
}).then(r => r.json());
return result.allowed;
}Queue the webhook for later if result.allowed is false. Use result.retry_after_ms to schedule the retry at the optimal time.
Export / bulk operation throttling
Limit expensive database export operations per user per hour to prevent one user from saturating your DB connection pool.
Node.js — export throttle
const API_KEY = process.env.DEVOPSIL_API_KEY;
async function checkExportLimit(userId: string) {
const result = await fetch('https://devopsil.com/api/v1/ratelimit/increment', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `export:${userId}`,
algorithm: 'fixed_window',
limit: 3,
window_seconds: 3600, // 3 exports per hour
}),
}).then(r => r.json());
return result;
}result.allowed gates the export. result.reset_at tells the user exactly when they can try again.
DDoS mitigation
Rate limit by IP at the edge of your application before requests reach business logic, stopping volumetric attacks without per-request infrastructure overhead.
Node.js — edge IP rate limit
const API_KEY = process.env.DEVOPSIL_API_KEY;
async function edgeRateLimit(ip: string) {
const result = await fetch('https://devopsil.com/api/v1/ratelimit/increment', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `ip:${ip}`,
algorithm: 'sliding_window',
limit: 200,
window_seconds: 60, // 200 req/min per IP
}),
}).then(r => r.json());
return result;
}Respond with 429 and no further processing if result.allowed is false. Sub-millisecond latency means this check adds negligible overhead.
Algorithm comparison
| Algorithm | Best for | Window type | Burst allowed |
|---|---|---|---|
| fixed_window | Simple quotas, billing periods | Hard reset | Yes |
| sliding_window | Per-minute / per-hour API limits | Rolling | No |
| token_bucket | Burst-tolerant throttling, AI tokens | Continuous | Yes |
How the API works
All requests use Bearer authentication. Your API key starts with rat_. Get one at /dashboard/api-keys.
Request
{
"key": "api_key:ak_9x2mp3z",
"algorithm": "sliding_window",
"limit": 1000,
"window_seconds": 3600
}Response
{
"allowed": true,
"limit": 1000,
"remaining": 847,
"used": 153,
"reset_at": "2024-03-15T15:00:00Z",
"retry_after_ms": null,
"algorithm": "sliding_window",
"key": "api_key:ak_9x2mp3z"
}Quick start
Get your API key
Create a free account and generate a key at /dashboard/api-keys. Your key starts with rat_.
Make your first call
Node.js
const API_KEY = process.env.DEVOPSIL_API_KEY; // starts with rat_
const result = await fetch('https://devopsil.com/api/v1/ratelimit/increment', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: 'user:usr_test_123',
algorithm: 'sliding_window',
limit: 100,
window_seconds: 60,
}),
}).then(r => r.json());
console.log(result.allowed, result.remaining);Act on the result
Node.js — handle response
if (!result.allowed) {
// Return 429 with standard headers
res.set('Retry-After', Math.ceil(result.retry_after_ms / 1000));
res.set('X-RateLimit-Limit', result.limit);
res.set('X-RateLimit-Remaining', 0);
return res.status(429).json({ error: 'Rate limit exceeded', reset_at: result.reset_at });
}
// Allowed — continue with the request
res.set('X-RateLimit-Remaining', result.remaining);