Getting Started
Sign up at ratelimitr.com, verify your email, and you'll get a tenant ID and can create your first API key from the dashboard.
Every request uses your API key in the x-api-key header — all rate limits are scoped to your account.
Rate Limit Check
POST https://api.ratelimitr.com/v1/check
Headers
x-api-key: rl_key_abc123def456
Content-Type: application/jsonRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| identifier | string | yes | Unique ID for the entity you're rate-limiting (user ID, IP address, session token, etc.) |
| tenantId | string | yes | Your tenant ID from the dashboard |
| endpoint | string | no | The endpoint being accessed (e.g., /api/users) — logged for analytics |
| method | string | no | HTTP method — logged for analytics |
| strategy | string | no | Override strategy: fixed_window, token_bucket, leaky_bucket, or sliding_window. Defaults to your plan's strategy |
| weight | integer | no | Cost of this request (default: 1). Set to 5 for expensive operations |
Responses
200 — Allowed
{
"allowed": true,
"remaining": 42,
"resetAt": 1718000000,
"limit": 100,
"strategy": "token_bucket"
}429 — Rate Limited
{
"allowed": false,
"remaining": 0,
"resetAt": 1718000060,
"limit": 100,
"strategy": "token_bucket",
"retryAfter": 45
}Examples
cURL
curl -X POST https://api.ratelimitr.com/v1/check \
-H "x-api-key: rl_key_abc123def456" \
-H "Content-Type: application/json" \
-d '{
"identifier": "user:123",
"tenantId": "tenant_abc",
"endpoint": "/api/resource"
}'JavaScript (with retry-with-backoff)
async function checkWithRetry(identifier, tenantId) {
let attempt = 0;
const maxRetries = 3;
while (attempt < maxRetries) {
const res = await fetch('https://api.ratelimitr.com/v1/check', {
method: 'POST',
headers: {
'x-api-key': 'rl_key_abc123def456',
'Content-Type': 'application/json'
},
body: JSON.stringify({ identifier, tenantId })
});
if (res.status === 429) {
const { retryAfter } = await res.json();
const delay = (retryAfter || Math.pow(2, attempt)) * 1000;
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
attempt++;
} else {
return await res.json();
}
}
throw new Error('Max retries exceeded');
}Python
import requests
response = requests.post(
'https://api.ratelimitr.com/v1/check',
headers={
'x-api-key': 'rl_key_abc123def456',
'Content-Type': 'application/json'
},
json={
'identifier': 'user:123',
'tenantId': 'tenant_abc',
'endpoint': '/api/resource'
}
)
print(response.json())WebSocket Live Stream
wss://api.ratelimitr.com/ws
Connect, authenticate with your API key, then subscribe to real-time channels.
Connection Flow
On connect, server responds:
{ "type": "connected", "availableChannels": ["events", "metrics", "alerts", "blocks"] }Authenticate:
{ "type": "authenticate", "apiKey": "rl_key_abc123def456" }Response:
{ "type": "authenticated", "timestamp": 1718000000 }Subscribe to channels:
{ "type": "subscribe", "channels": ["events", "metrics"] }Response:
{ "type": "subscribed", "channels": ["events", "metrics"], "timestamp": 1718000000 }Unsubscribe:
{ "type": "unsubscribe", "channels": ["events"] }Ping / Pong (keepalive):
{ "type": "ping" } → { "type": "pong", "timestamp": 1718000000 }Channels
Real-time events come through on subscribed channels:
events channel — every rate limit decision:
{
"type": "block",
"data": {
"identifier": "user:123",
"endpoint": "/api/resource",
"strategy": "token_bucket",
"remaining": 0
},
"timestamp": 1718000000
}metrics channel — every 5 seconds:
{
"type": "metrics",
"data": {
"connectedClients": 12,
"usedMemory": "2.5M",
"totalCommandsProcessed": 104200,
"instantaneousOpsPerSec": 340,
"uptime": 7
},
"timestamp": 1718000000
}JavaScript Example
const ws = new WebSocket('wss://api.ratelimitr.com/ws');
ws.onopen = () => {
console.log('Connected to RateLimitr');
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'connected') {
ws.send(JSON.stringify({
type: 'authenticate',
apiKey: 'rl_key_abc123def456'
}));
}
else if (msg.type === 'authenticated') {
ws.send(JSON.stringify({
type: 'subscribe',
channels: ['events', 'metrics']
}));
}
else if (msg.type === 'subscribed') {
console.log('Subscribed to:', msg.channels);
}
else {
console.log('Incoming event:', msg);
}
};Rate Limiting Strategies
| Strategy | Plans | Behavior |
|---|---|---|
| fixed_window | Free, Pro, Enterprise | Counts requests in a fixed time window (e.g., 1000 per minute). Resets at the boundary. Simple and predictable. |
| token_bucket | Pro, Enterprise | Tokens refill at a steady rate. Allows bursts up to bucket capacity. Smooths traffic over time. |
| leaky_bucket | Pro, Enterprise | Processes requests at a constant rate. Excess is queued and processed as capacity frees up. |
| sliding_window | Enterprise | Evaluates request count over a rolling time window using data from the previous window. No traffic spikes at boundaries. |
Strategy resolution order: ① request body's strategy field, ② per-key override (set in dashboard), ③ your plan's default strategy.
API Keys
Create and manage keys from the dashboard at /dashboard/api-keys. Each key can have:
- Scopes: read, write, admin
- Rate limit override: Custom limits per key (requests/second, burst, window, strategy)
- Per-endpoint limits: Different limits for different routes
- Expiration: Auto-revoke after a set date
Keys can also be managed programmatically:
| Method | Path | Description |
|---|---|---|
| POST | /api-keys/keys | Create key: { name, scopes?, rateLimitOverride?, expiresAt? } |
| GET | /api-keys/keys | List keys: ?limit&offset&status&search |
| PATCH | /api-keys/keys/:keyId | Update key |
| DELETE | /api-keys/keys/:keyId | Revoke key |
Rate Limit Headers
Every response from the check endpoint includes:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Max requests in the current window |
| X-RateLimit-Remaining | Requests remaining in this window |
| X-RateLimit-Reset | Unix timestamp when the window resets |
| Retry-After | Seconds to wait (only on 429 responses) |
Error Codes
| Code | Meaning |
|---|---|
| 400 | Invalid request — check your body fields |
| 401 | Bad or missing API key — check your x-api-key header |
| 429 | Rate limit exceeded — use Retry-After to back off |