All specs
infrastructuremedium complexity

Rate Limiting & Abuse Prevention

Used in 7 specs

Prevent abuse, contain bursts, and enforce fair use across authenticated APIs, public endpoints, and expensive operations.

Options

Rate Limit Algorithm*

Count requests per user per minute; reset at the minute boundary.
Counts over a rolling window to eliminate boundary bursts.
Each identity has a bucket that refills at a steady rate; each request consumes a token.

What to Limit By*

Limits keyed on client IP.
Limits keyed on user ID or API key.
Expensive endpoints (search, export) get lower limits than cheap ones.
Aggregate limit across all users in a workspace.

Abuse Prevention Layer

hCaptcha / Turnstile on signup, login, and password reset — triggered on threshold breach, not every request.
ML-driven client fingerprinting to score requests as human/bot before routing.
Cloudflare, AWS WAF, or Fastly with OWASP and bot rule packs in front of your origin.

Response Behavior*

Return HTTP 429 with Retry-After, X-RateLimit-Limit, and X-RateLimit-Remaining so clients back off correctly.
After threshold, delay responses by seconds instead of returning 429.

Decision Points

Do you have unauthenticated endpoints (signup, login, public API)?

If yes

Add per-IP limits on those endpoints plus CAPTCHA on threshold. Assume credential-stuffing is attempted on day one.

If no

Per-user limits on authenticated APIs are sufficient.

Do different customer tiers pay for different rate limits?

If yes

Keyed-on-API-key limits with plan-configured thresholds; expose a usage endpoint.

If no

A single default limit keeps configuration simple.

Do you expect adversarial traffic (credential stuffing, scraping, spam)?

If yes

Use sliding window or token bucket — fixed window leaks under boundary timing attacks. Pair with WAF and bot detection.

If no

Fixed-window with Redis INCR + EXPIRE is cheap, simple, and sufficient.

Do you have legitimate burst patterns (batch imports, bulk API calls)?

If yes

Token bucket is the right model — allows bursts while enforcing a sustained rate. The standard for commercial API gateways.

If no

Sliding window is simpler and has lower memory overhead.

Do you run multiple server nodes behind a load balancer?

If yes

Use centralized Redis for rate-limit state (Upstash Ratelimit, redis-cell). Per-node local counters let attackers get N×limit by rotating through nodes.

If no

In-process counters are fine for single-node deployments and dramatically cheaper.

Should users get a warning before they hit a hard limit?

If yes

Emit soft-limit warnings via response headers (X-RateLimit-Remaining) and optionally an in-app notification when usage >80%. Prevents angry support tickets.

If no

Silent throttling at the hard limit is simpler but worse UX — only acceptable for internal APIs.

Do you have enterprise customers who negotiate custom limits?

If yes

Build an admin override table keyed on tenant/API-key. Do not hardcode limits — operations team will need to raise them without deploys.

If no

Static per-tier limits in config are simpler and easier to reason about.

Can a single user enqueue unbounded background jobs (imports, scrapes, AI calls)?

If yes

Rate-limit the enqueue side separately from the API side. Prevents queue-flooding attacks that bypass request-layer limits.

If no

API-layer limits are sufficient; background jobs are produced by your own code only.

Do you have legitimate short bursts you want to allow (e.g. pagination fan-out)?

If yes

Use token bucket with a burst allowance (bucket size > refill rate). Clients can consume the bucket quickly, then settle.

If no

A flat rate is simpler — bursts are a policy decision, not a default.

Are you exposed to L3/L4 DDoS (public API, unauthenticated endpoints)?

If yes

Put Cloudflare, AWS Shield, or Fastly in front of your origin. Application-layer rate limiting cannot absorb network-layer floods.

If no

Application-layer limits are sufficient for authenticated-only APIs.

Do some endpoints cost 100x more than others (AI calls, complex queries, exports)?

If yes

Rate-limit by computational cost (credits/tokens per request) not by request count. Pricing and abuse protection align naturally.

If no

Request-count limits are simpler and sufficient when endpoint costs are roughly uniform.

Do specific features (uploads, AI generations) have their own cost or quota model?

If yes

Add per-feature limits in addition to global ones. A user at their upload quota should still be able to read the API.

If no

Per-route limits are enough and keep configuration centralized.

Is this a public developer API with SDKs / third-party integrations?

If yes

Always return X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After headers. Well-behaved clients need them to back off correctly.

If no

Minimum viable is Retry-After on 429 responses — detailed headers are nice-to-have for internal APIs.

Do you have health checks, metrics endpoints, or internal traffic hitting rate-limited routes?

If yes

Exempt health checks and internal service-to-service calls by IP allowlist or dedicated service tokens. Otherwise monitoring will trip your own limits.

If no

Default behavior — all traffic counts — is simpler and auditable.

Do you have authentication endpoints at risk of credential stuffing?

If yes

Rate-limit failed logins separately (per-account + per-IP), with exponential backoff and lockout after N attempts. Combine with CAPTCHA on threshold.

If no

General per-IP limits are insufficient for auth — always treat login and password reset as a separate budget.

Tradeoffs

UXPer-IP limits only

False positives behind corporate NATs; attackers bypass with rotating proxies

ScalabilityPer-tenant limits enabled

Noisy-neighbor protection — one tenant cannot starve others

CostToken bucket chosen

Allows bursts but requires a per-identity bucket state in Redis — higher memory footprint

LatencyWAF added in front

Meaningful latency cost at the edge if the WAF is geographically distant from users

Implementation Examples

Cloudflare Rate Limiting

Edge-based rate limiting with sophisticated dimensions and bot-score integration.

Upstash Ratelimit

Serverless-friendly rate limiter using Redis with sliding-window and token-bucket algorithms.

Envoy / Kong rate limiting filters

API-gateway-level rate limiting with global consistency via an external service.

Used by specs

Slack-like Messaging AppE-commerce StorefrontSaaS StarterDeveloper Tool / API ProductSocial / Community AppAI-Powered SaaSMarketplace Platform