---
title: "Limit how often anyone can call your APIs · Agent Wranglers"
url: https://agentwranglers.se/playbook/website/security/rate-limits
updated: 2026-10-20
licence: "All rights reserved"
---

# Limit how often anyone can call your APIs

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Security](https://agentwranglers.se/playbook/website/security)
- Rule: Put a rate limit on every endpoint that does work for each request, such as APIs, agent endpoints, forms and report collectors.
- How: Count requests per client over a short window, such as 60 a minute. Answer `429 Too Many Requests` with a `Retry-After` header when a client goes over, as [say when to retry](https://agentwranglers.se/playbook/api-design/errors/retry-after) requires. Consider also sending the `RateLimit` headers, which are still an IETF draft, as [tell clients their rate limit](https://agentwranglers.se/playbook/api-design/reliability/rate-limit-headers) says. Behind a proxy, trust its forwarded address, or every visitor counts as one. Logins need more, such as two-factor login, as in [slow down password guessing](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/login-guessing).
- Check: Send more requests than the limit in a loop. The extra ones get 429 with `Retry-After`, and normal pages are not affected.

Example:

```http
HTTP/2 429
retry-after: 42
ratelimit-policy: "per-minute";q=60;w=60
ratelimit: "per-minute";r=0;t=42
```

```js
// Express: one limiter in front of every endpoint that does work
import rateLimit from 'express-rate-limit';
app.set('trust proxy', 1);
app.use(['/api', '/mcp', '/ask'], rateLimit({ windowMs: 60_000, limit: 60, standardHeaders: 'draft-8' }));
```

```python
# Flask with Flask-Limiter: 429 and Retry-After past 60 a minute
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1)
limiter = Limiter(get_remote_address, app=app, headers_enabled=True, storage_uri="redis://localhost:6379")

@app.post("/api/orders")
@limiter.limit("60 per minute")
def create_order(): ...
```

```nginx
# nginx in front of any stack
limit_req_zone $binary_remote_addr zone=work:10m rate=60r/m;
location /api/ { limit_req zone=work burst=10 nodelay; limit_req_status 429; proxy_pass http://app; }
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers website playbook: https://agentwranglers.se/playbook/website/security/rate-limits`.

- Previous: [Wipe browser data on sign-out](https://agentwranglers.se/playbook/website/security/clear-site-data)
- [Security](https://agentwranglers.se/playbook/website/security)
