Tiered Rate Limiting — Different Limits for Free, Pro, and Enterprise Plans
In this tutorial, you will learn about Tiered Rate Limiting. We cover key concepts, practical examples, and best practices to help you master this topic.
Tiered rate limiting assigns different rate limits, quotas, and features to different subscription tiers, allowing API providers to monetize access by offering graduated service levels from free to enterprise.
What You'll Learn
- How to design a multi-tier rate limiting Strategy
- How to map API keys to tiers and enforce tier-specific limits
- How to handle tier upgrades and downgrades gracefully
Why It Matters
Free tiers attract developers and build adoption. Pro tiers generate revenue. Enterprise tiers provide high-volume access for large customers. Tiered rate limiting enforces these boundaries, ensuring each customer gets the service level they pay for while incentivizing upgrades.
Real-World Use
DodaTech's API offers three tiers: Free (10 req/min, 1000 req/day), Pro ($49/mo, 100 req/min, 50000 req/day), and Enterprise (custom pricing, 1000 req/min, unlimited quota). Tiered rate limiting enforces these limits and returns appropriate headers showing the current tier.
flowchart LR
A["API Request"] --> B{"Identify Tier"}
B -->|"Free"| C["10 req/min\n1000 req/day"]
B -->|"Pro"| D["100 req/min\n50000 req/day"]
B -->|"Enterprise"| E["1000 req/min\nCustom quota"]
C --> F{"Within\nlimits?"}
D --> F
E --> F
F -->|Yes| G["Process"]
F -->|No| H["429 + Upgrade\nsuggestion"]
style C fill:#fef3c7,stroke:#d97706
style D fill:#dbeafe,stroke:#2563eb
style E fill:#bbf7d0,stroke:#16a34a
style H fill:#fecaca,stroke:#dc2626
Tier Configuration
TIER_CONFIG = {
"free": {
"rate_limit": 10,
"rate_window": 60,
"daily_quota": 1000,
"monthly_quota": 10000,
"features": ["basic_search", "public_data"],
"price_monthly": 0
},
"pro": {
"rate_limit": 100,
"rate_window": 60,
"daily_quota": 50000,
"monthly_quota": 500000,
"features": ["advanced_search", "export", "webhooks"],
"price_monthly": 49
},
"enterprise": {
"rate_limit": 1000,
"rate_window": 60,
"daily_quota": 500000,
"monthly_quota": None, # Unlimited
"features": ["all", "dedicated_support", "sla", "custom_limits"],
"price_monthly": "custom"
}
}
def get_tier_config(api_key):
"""Look up the tier for a given API key from the database"""
# In production, query your database
tier_map = {
"key_free_abc": "free",
"key_pro_def": "pro",
"key_ent_ghi": "enterprise"
}
tier = tier_map.get(api_key, "free")
return TIER_CONFIG[tier], tier
Tier Enforcement Middleware
from flask import Flask, request, jsonify, g
import redis
from functools import wraps
app = Flask(__name__)
r = redis.Redis(host='localhost', port=6379, db=0)
def enforce_tier_limits(f):
@wraps(f)
def decorated(*args, **kwargs):
api_key = request.headers.get('X-API-Key')
if not api_key:
return jsonify({"error": "missing_api_key"}), 401
config, tier = get_tier_config(api_key)
if not config:
return jsonify({"error": "invalid_api_key"}), 403
rate_key = f"rl:tier:{api_key}:{int(__import__('time').time() / config['rate_window'])}"
current = r.get(rate_key)
if current and int(current) >= config["rate_limit"]:
upgrade_tiers = {"free": "pro", "pro": "enterprise"}
suggestion = upgrade_tiers.get(tier)
return jsonify({
"error": "rate_limit_exceeded",
"tier": tier,
"limit": config["rate_limit"],
"upgrade_suggestion": suggestion,
"upgrade_url": f"https://doda.example.com/upgrade?to={suggestion}"
}), 429
r.incr(rate_key)
r.expire(rate_key, config["rate_window"])
g.tier = tier
g.tier_config = config
return f(*args, **kwargs)
return decorated
Feature Gating by Tier
def requires_feature(feature_name):
"""Decorator that checks if the current tier has access to a feature"""
def decorator(f):
@wraps(f)
def decorated(*args, **kwargs):
allowed_features = g.tier_config["features"]
if "all" not in allowed_features and feature_name not in allowed_features:
return jsonify({
"error": "feature_not_available",
"feature": feature_name,
"tier": g.tier,
"message": f"Upgrade to access {feature_name}",
"upgrade_url": f"https://doda.example.com/upgrade"
}), 402
return f(*args, **kwargs)
return decorated
return decorator
@app.route('/api/export')
@enforce_tier_limits
@requires_feature("export")
def export_data():
return jsonify({"data": "exported data"})
Common Mistakes
1. Making Tiers Too Similar
If free and pro tiers have nearly identical limits, few users upgrade. Ensure meaningful differences in limits and features.
2. Not Communicating Upgrade Paths
Rate limit errors should include upgrade suggestions. A clear upgrade path converts frustrated users into paying customers.
3. Hardcoding Tier Configurations
Store tier configurations in a database or config file, not in code. This allows changing limits without deploying new code.
4. Ignoring Enterprise Custom Limits
Enterprise customers often need custom limits. Support per-customer overrides that bypass standard tier configurations.
5. Not Testing Tier Boundaries
Test that each tier's limits are enforced correctly. A bug that gives Pro users Free limits leads to support tickets and churn.
Practice Questions
- What tiers are common for API rate limiting?
- How do you map an API key to a tier?
- Why should rate limit errors suggest upgrades?
- How do you handle custom enterprise limits?
- What is feature gating by tier?
Answers
- Free, Pro, Enterprise (with graduated limits). 2. Look up the tier in a database by the API key. 3. To convert limited users into paying customers. 4. Support per-customer overrides in the tier configuration. 5. Restricting access to certain features based on the subscription tier.
Challenge
Build a tier management service that allows admin users to create custom tiers with arbitrary rate limits, quotas, and feature flags, assigns API keys to tiers, and provides an API for checking what tier a key belongs to.
FAQ
Mini Project
Create a complete tiered rate limiting system with: a YAML-based tier configuration, a FastAPI middleware that enforces limits per tier, a Stripe integration for upgrades, Webhook handling for tier changes, and a customer dashboard showing current usage vs tier limits with upgrade prompts.
What's Next
- Learn about rate limit headers for client-side consumption
- Explore the retry-after header for client backoff
- Continue to rate limit testing strategies with load testing tools
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro