Rate Limits
All Magne API endpoints are rate-limited per IP address using a sliding window algorithm with two tiers.
Tiers
| Tier | Max Requests | Window | Applies To |
|---|
| Auth | 5 requests | 60 seconds | /v1/auth/register, /v1/auth/login, /v1/auth/verify-email, /v1/auth/resend-code, /v1/auth/forgot-password, /v1/auth/reset-password |
| General | 300 requests | 60 seconds | All other endpoints |
Additionally, webhook execution has its own per-webhook rate limit:
| Tier | Max Requests | Window | Applies To |
|---|
| Webhook | 30 requests | 60 seconds | POST /v1/webhooks/:id/:token (per webhook ID) |
When rate-limited, the API returns a 429 Too Many Requests response with:
| Header | Description |
|---|
Retry-After | Seconds to wait before retrying |
{
"error": "Too many requests. Please try again later."
}
Retry Strategy
Implement exponential backoff when you receive a 429 response. Start
with the Retry-After value, then double the wait time on each subsequent
retry.
Recommended implementation:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const res = await fetch(url, options);
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get("Retry-After") || "1");
const backoff = retryAfter * Math.pow(2, i);
await new Promise((r) => setTimeout(r, backoff * 1000));
continue;
}
return res;
}
throw new Error("Rate limit exceeded after max retries");
}
IP Detection
Rate limits are tracked by client IP. The server checks headers in this order:
X-Forwarded-For (first entry, if behind a reverse proxy)
X-Real-IP
- Fallback: connection IP