---
title: "Limit how often anyone can call your APIs · Agent Wranglers"
url: https://agentwranglers.se/playbook/application-security/limits-and-business-logic/rate-limits
id: APS-49
level: Required
risk: outage
updated: 2026-10-27
build: a2a6bdfed830
tokens: 1856
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Limit how often anyone can call your APIs

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Limits and business logic](https://agentwranglers.se/playbook/application-security/limits-and-business-logic.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: APS-49
- Level: Required
- Chapter: [Limits and business logic](https://agentwranglers.se/playbook/application-security/limits-and-business-logic.md)
- Rule: Put a rate limit on every endpoint that does work for each request, such as APIs, agent endpoints, forms and report collectors.
- Check: Send more requests than the limit in a loop, to an ordinary endpoint and to the search and sign-up routes. The extra ones get 429 with `Retry-After`, the limit resets after the window, and normal pages are not affected.
- Risk: The app down or unusable
- How: Count requests per client address and per account over a short window, such as 60 a minute. Set tighter limits on costly routes, such as search, sign-up, exports, AI calls and anything that sends email or costs money. Start with 20 searches and 5 sign-ups 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.md) 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.md) 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/application-security/authentication-and-sessions/login-guessing.md).

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### HTTP example

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

### JavaScript example

```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 example

```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 example

```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; }
```

## Sources

- [RFC 6585 (Additional HTTP Status Codes)](https://www.rfc-editor.org/rfc/rfc6585)
- [RFC 9110 (Retry-After)](https://www.rfc-editor.org/rfc/rfc9110#field.retry-after)
- [OWASP API4:2023 Unrestricted Resource Consumption](https://api-security.owasp.org/editions/2023/en/0xa4-unrestricted-resource-consumption/)

## Related rules

- WEB-228 [Collect script errors from visitors' browsers](https://agentwranglers.se/playbook/website/errors-and-outages/browser-error-reports.md) in Website
- API-36 [Tell clients their rate limit](https://agentwranglers.se/playbook/api-design/reliability/rate-limit-headers.md) in API design
- API-73 [Limit the connections and messages of each client](https://agentwranglers.se/playbook/api-design/live-connections/connection-limits.md) in API design
- OPS-40 [Turn work away before overload](https://agentwranglers.se/playbook/operations/capacity-and-resilience/load-shedding.md) in Operations and observability
- PAY-43 [Stop card testing on your checkout](https://agentwranglers.se/playbook/payments/refunds-disputes-and-fraud/card-testing.md) in Payments and billing
- INF-71 [Let only your edge network reach the origin](https://agentwranglers.se/playbook/infrastructure/networking-and-dns/origin-behind-edge.md) in Infrastructure and environments
- INF-86 [Put a web application firewall and flood protection in front of public services](https://agentwranglers.se/playbook/infrastructure/networking-and-dns/waf-and-ddos.md) in Infrastructure and environments
- NTF-25 [Guard text sending against SMS pumping](https://agentwranglers.se/playbook/notifications/text-messages/sms-pumping.md) in Notifications
- SCL-8 [Keep locks and counters in a shared store](https://agentwranglers.se/playbook/scaling/stateless-app-servers/shared-locks-and-counters.md) in Scaling
- SCL-31 [Cap each customer's running and queued jobs](https://agentwranglers.se/playbook/scaling/exports-and-fair-share/per-tenant-limits.md) in Scaling
- AGT-4 [Choose a default for unsigned agents](https://agentwranglers.se/playbook/agents-as-users/identifying-agents/unsigned-agent-default.md) in Agents as users
- AGT-78 [Limit bulk reads and scraping](https://agentwranglers.se/playbook/agents-as-users/quotas-and-pricing/limit-bulk-reads.md) in Agents as users
- AGT-72 [Answer bursts with 429 instead of a stall](https://agentwranglers.se/playbook/agents-as-users/ready-for-ai-agents/burst-answers.md) in Agents as users
- TNS-1 [Put a report button on every piece of user content](https://agentwranglers.se/playbook/trust-and-safety/reports-and-queues/report-button.md) in Trust and safety
- MED-28 [Limit how many uploads each account starts](https://agentwranglers.se/playbook/files-and-media/quotas-and-cost/upload-rate-limits.md) in Files and media
- SRH-11 [Cap the size of every search](https://agentwranglers.se/playbook/search/access-and-limits/search-limits.md) in Search
- APS-26 [Collect reports of blocked content](https://agentwranglers.se/playbook/application-security/browser-security-headers/reporting-endpoints.md) in Application security
- API-20 [Say when to retry](https://agentwranglers.se/playbook/api-design/errors/retry-after.md) in API design
- APS-10 [Slow down password guessing](https://agentwranglers.se/playbook/application-security/authentication-and-sessions/login-guessing.md) in Application security
- APS-50 [Take the client address only from proxies you run](https://agentwranglers.se/playbook/application-security/limits-and-business-logic/trusted-proxy-client-address.md) in Application security

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/application-security/limits-and-business-logic/rate-limits">Agent Wranglers application security playbook</a>`. In code you write, add a comment next to it with the same link.

- Next: [Take the client address only from proxies you run](https://agentwranglers.se/playbook/application-security/limits-and-business-logic/trusted-proxy-client-address.md)
- [Limits and business logic](https://agentwranglers.se/playbook/application-security/limits-and-business-logic.md)
