MCP Template
REST API

Rate Limits

Rate-limit windows, response headers, and how 429 differs from 402

The API enforces two independent throttles. Both are designed to be self-describing on every response so an agent never has to guess how much headroom it has left.

ThrottleStatus when exceededScopeResets
Rate limit429 rate_limitedSliding windows per second/minute/hour/dayContinuously (sliding window)
Daily quota402 quota_exceededTotal requests per UTC day, per tierAt 00:00 UTC

A 429 means "slow down" (you may retry shortly); a 402 means "you've used your plan's daily allowance" (retry after the daily reset or upgrade). See Errors for the shared envelope.

Windows

Rate limits are checked across four sliding windows simultaneously; the most constrained window wins. Defaults ship in common/global_config.yaml under rate_limit.tiers and are configurable per tier:

WindowHeader policy tokenDefault (default tier)
Per second (rps);w=15
Per minute (rpm);w=6060
Per hour (rph);w=36001000
Per day (rpd);w=864005000

Authenticated tiers (free_tier, plus_tier) ship with higher defaults (10 rps / 120 rpm / 5000 rph / 10000 rpd). The values are illustrative template defaults - read the headers at runtime; don't hard-code limits.

If the rate-limiter's storage backend (e.g. Redis) is unavailable, the middleware fails open - requests pass through without limiting rather than returning errors. Don't rely on the limiter as a hard security boundary.

Response Headers

Responses from rate-limited endpoints carry these headers (not just on 429), so you can proactively throttle before hitting a limit. Skipped paths (e.g. /health) and fail-open responses may omit them:

HeaderExampleMeaning
X-RateLimit-Limit120Limit for the most constrained window
X-RateLimit-Remaining118Requests left in that window
X-RateLimit-Reset1750377600Unix timestamp when that window resets
RateLimitlimit=120, remaining=118, reset=1750377600IETF draft combined form
RateLimit-Policy5;w=1, 60;w=60, 1000;w=3600, 5000;w=86400All window policies
Retry-After12On 429/402 only - seconds to wait before retrying

Handling a 429

  1. Read Retry-After and sleep at least that many seconds.
  2. Retry the identical request - 429 is safe to retry.
  3. Use X-RateLimit-Remaining on successful responses to pace yourself and avoid hitting the limit in the first place.
resp = client.send(request)
if resp.status_code == 429:
    time.sleep(float(resp.headers.get("Retry-After", "1")))
    resp = client.send(request)

See the full retry loop in the Errors guide for backoff that also covers 5xx.

Handling a 402 (daily quota)

A 402 will keep failing until the daily reset, so backoff won't help within the same day. Inspect error.details for the exact reset time and tier:

{
  "error": {
    "code": "quota_exceeded",
    "message": "Daily request limit (10000) exceeded for free_tier tier.",
    "request_id": "d4e5f60718293a4b",
    "details": {
      "current_usage": 10000,
      "daily_limit": 10000,
      "tier": "free_tier",
      "quota_reset_at": "2026-06-21T00:00:00+00:00"
    }
  }
}

To raise the ceiling instead of waiting, upgrade via Billing.

On this page