Skip to content

Rate Limiting

Craft Easy API uses Slowapi (built on top of limits) to enforce token-bucket rate limiting on all endpoints.

Configuration

Setting Default Description
RATE_LIMIT_ENABLED true Enable/disable rate limiting globally
RATE_LIMIT_DEFAULT "100/minute" Default limit for all endpoints
RATE_LIMIT_AUTH "10/minute" Stricter limit for authentication endpoints
RATE_LIMIT_STORAGE_URI "memory://" Storage backend URI

Rate Limit Key

The limiter identifies callers using a smart key function:

  • Authenticated users: keyed by user:{user_id} — ensures per-user limits regardless of IP
  • Anonymous requests: keyed by the client's IP address

This prevents one user behind a shared IP (e.g., corporate NAT) from exhausting the limit for everyone.

Storage Backends

Backend URI Use Case
In-memory memory:// Development, single-instance deployments
Redis redis://host:6379 Production, multi-instance deployments

For multi-instance deployments behind a load balancer, use Redis so all instances share the same rate limit counters.

Response on Limit Exceeded

When a client exceeds the rate limit, the API returns:

HTTP/1.1 429 Too Many Requests
Retry-After: 42
X-Request-ID: abc-123

{
  "error": "RATE_LIMIT_EXCEEDED",
  "message": "Rate limit exceeded",
  "retry_after": 42
}

The Retry-After header indicates when the client can retry (in seconds).

Per-Route Limits

You can apply custom limits to specific routes using Slowapi decorators:

from slowapi import Limiter

@app.get("/expensive-report")
@limiter.limit("5/minute")
async def expensive_report():
    ...

Auth Rate Limiting

Authentication endpoints (login, OTP, verify) have a stricter rate limit configured via RATE_LIMIT_AUTH. This protects against brute-force attacks:

RATE_LIMIT_AUTH = "10/minute"  # Max 10 auth attempts per minute per user/IP

Additional auth-specific protections are covered in Abuse Protection.