A SaaS API should limit both individual callers and entire tenants. A user-only limit does not stop one customer from creating many users or API keys, while a tenant-only limit lets one user consume the customer’s whole allowance.
Last updated: September 8, 2026.
$keys = [
"rate:tenant:{$tenantId}:minute",
"rate:user:{$tenantId}:{$userId}:minute",
];
foreach ($keys as $key) {
if (!$limiter->allow($key, $limit, 60)) {
http_response_code(429);
exit('Rate limit exceeded');
}
}The example uses trusted tenant and user IDs from authentication. A distributed application should store counters in a shared, atomic system rather than process memory.
Choose several limit dimensions
- Per IP: useful before login and for basic abuse protection.
- Per user or API key: identifies a single caller.
- Per tenant: protects shared capacity and enforces plan-level quotas.
- Per operation: assigns tighter limits to exports, reports, searches, and AI or third-party calls.
Use a token bucket or sliding-window implementation when short bursts are legitimate. Reserve concurrency limits for long-running work so ten large exports cannot occupy every worker even when request counts remain low.
Return useful responses
Respond with HTTP 429 Too Many Requests and a Retry-After value when the client can safely retry later. Document whether limits apply by second, minute, day, or billing period. Avoid revealing another tenant’s usage.
Connect limits to operations
Rate limiting protects immediate requests; queues and quotas protect deferred work. Apply tenant-aware limits when accepting background jobs, then monitor sustained consumption to detect a noisy neighbor. Record administrative limit changes in audit logs.
Fail safely when the limiter is unavailable. For sensitive or expensive endpoints, deny or apply a conservative local fallback. For low-risk reads, a short bounded fallback may preserve availability.