ZuploZuplo
LoginStart for Free
  • Documentation
  • API Reference
Introduction
Getting Started
    Develop on the web portal
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingDynamic MCP Server - Quickstart
    Develop locally with the CLI
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingDynamic MCP Server - Quickstart
Concepts
Development
Policies
Handlers
API Keys
Rate Limiting
    Getting startedHow it works
    Policies
    Guides
      Dynamic rate limitingCombining policiesPer-user rate limitsMonitoring & troubleshooting
MCP Server
MCP Gateway
AI Gateway
Developer Portal
Monetization
Deploying & Source Control
Analytics
Observability
Networking & Infrastructure
Account Management
Programming API
Build with AI
Zuplo CLI
Migration Guides
Platform LimitsSecuritySupportTrust & ComplianceChangelog
powered by Zudoku
Guides

Combining rate limit policies

Real-world APIs rarely need just one rate limiting boundary. A payment endpoint might need a per-minute burst limit to protect against runaway scripts and a per-hour cap to enforce fair usage. A monetized API might pair a monthly quota with a per-second spike guard. Zuplo supports all of these patterns by letting you stack multiple policies on the same route.

Multiple rate limits on one route

You can apply two or more rate limiting policies to a single route. Each policy maintains its own counter independently, and the request must pass every policy to reach the backend.

A common pattern is combining a short-window burst limit with a longer-window sustained limit. The following example enforces both a 1,000-requests-per-hour ceiling and a 100-requests-per-minute burst limit on the same route.

Define the policies

config/policies.json
{ "policies": [ { "name": "rate-limit-hourly", "policyType": "rate-limit-inbound", "handler": { "export": "RateLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "rateLimitBy": "user", "requestsAllowed": 1000, "timeWindowMinutes": 60 } } }, { "name": "rate-limit-per-minute", "policyType": "rate-limit-inbound", "handler": { "export": "RateLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "rateLimitBy": "user", "requestsAllowed": 100, "timeWindowMinutes": 1 } } } ] }

Attach them to a route

List both policies in the route's inbound pipeline. Place the longest time window first:

config/routes.oas.json (excerpt)
{ "x-zuplo-route": { "policies": { "inbound": ["rate-limit-hourly", "rate-limit-per-minute"] } } }

Apply the longest time window first. If a caller already exhausted the hourly quota, the request is rejected immediately without incrementing the per-minute counter. This avoids wasting counter writes on requests that would fail anyway.

Each policy tracks its own sliding window counter scoped by its name. A request that passes the hourly check still gets evaluated against the per-minute check. If either policy rejects the request, the client receives a 429 Too Many Requests response.

Rate limiting vs. quotas

Rate limiting and quotas both cap usage, but they solve different problems.

AspectRate limitingQuota
Time windowShort: seconds, minutes, or hoursLong: hourly, daily, weekly, or monthly
PurposeProtect backends from traffic spikesEnforce billing-period usage caps
Counter resetSliding window rolls continuouslyFixed period anchored to a start date
Typical use"100 requests per minute per user""10,000 requests per month per subscription"
PolicyRate LimitingQuota

Use rate limiting when you need to smooth traffic and prevent bursts. Use quotas when you need to enforce a usage allowance over a billing cycle. In many APIs, you use both together: a monthly quota to cap total usage and a per-minute rate limit to prevent any single caller from overwhelming the backend within that quota.

Example: quota plus rate limit

config/policies.json
{ "policies": [ { "name": "monthly-quota", "policyType": "quota-inbound", "handler": { "export": "QuotaInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "period": "monthly", "quotaBy": "user", "allowances": { "requests": 10000 } } } }, { "name": "burst-rate-limit", "policyType": "rate-limit-inbound", "handler": { "export": "RateLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "rateLimitBy": "user", "requestsAllowed": 100, "timeWindowMinutes": 1 } } } ] }

On the route, place the quota policy first so that callers who already used their monthly allowance are rejected before the rate limit counter is incremented:

config/routes.oas.json (excerpt)
{ "x-zuplo-route": { "policies": { "inbound": ["monthly-quota", "burst-rate-limit"] } } }

Rate limiting with monetization

The Monetization policy handles subscription validation, quota enforcement, and metering in one step. It already enforces billing-period usage limits tied to the customer's plan, so you do not need a separate quota policy on monetized routes.

Rate limiting is still valuable alongside monetization. A customer with a 50,000 requests-per-month plan could theoretically send all 50,000 requests in a single minute, which would overwhelm your backend even though it falls within the monthly allowance. Adding a rate limiting policy prevents that spike.

config/routes.oas.json (excerpt)
{ "x-zuplo-route": { "policies": { "inbound": ["monetization-inbound", "rate-limit-per-minute"] } } }

The monetization policy handles API key authentication internally. You do not need a separate api-key-auth policy on monetized routes. Place the monetization policy first so that request.user is populated before the rate limit policy runs.

These two layers are complementary:

  • Monetization enforces monthly or billing-period usage limits and tracks metered usage for billing.
  • Rate limiting enforces per-minute or per-second spike protection to keep your backend healthy.

Counter scoping

Rate limit counters are scoped by the policy's name field combined with the caller identifier (user, IP, or custom key). Understanding this scoping is important when you apply the same policy type to multiple routes.

Shared counters

If two routes reference the same policy name, they share a counter. A caller who makes 60 requests to /orders and 40 requests to /products — both using a policy named rate-limit-per-minute — counts as 100 total requests against that policy's limit.

config/routes.oas.json (excerpt)
{ "paths": { "/orders": { "get": { "x-zuplo-route": { "policies": { "inbound": ["rate-limit-per-minute"] } } } }, "/products": { "get": { "x-zuplo-route": { "policies": { "inbound": ["rate-limit-per-minute"] } } } } } }

Shared counters are useful when you want a single global limit that applies across all routes for a given caller.

Independent counters

To give each route its own counter, create separate policy instances with different names:

config/policies.json
{ "policies": [ { "name": "rate-limit-orders", "policyType": "rate-limit-inbound", "handler": { "export": "RateLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "rateLimitBy": "user", "requestsAllowed": 100, "timeWindowMinutes": 1 } } }, { "name": "rate-limit-products", "policyType": "rate-limit-inbound", "handler": { "export": "RateLimitInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "rateLimitBy": "user", "requestsAllowed": 200, "timeWindowMinutes": 1 } } } ] }

Now a caller can make 100 requests per minute to /orders and 200 requests per minute to /products independently. Exhausting the orders limit does not affect the products limit.

If you duplicate a policy definition and forget to change the name, both routes share the same counter. Always verify that policy names are distinct when you intend independent counters.

Related resources

  • Rate Limiting policy reference
  • Complex Rate Limiting policy reference
  • Quota policy reference
  • Monetization policy
  • How rate limiting works
  • Dynamic Rate Limiting
Edit this page
Last modified on June 11, 2026
Dynamic rate limitingPer-user rate limits
On this page
  • Multiple rate limits on one route
    • Define the policies
    • Attach them to a route
  • Rate limiting vs. quotas
    • Example: quota plus rate limit
  • Rate limiting with monetization
  • Counter scoping
    • Shared counters
    • Independent counters
  • Related resources
JSON
JSON
JSON
JSON
JSON
JSON
JSON