Rate Limits
Optropic enforces rate limits to ensure fair usage and platform stability. Limits vary by subscription tier and endpoint.
Rate Limit Tiers
| Tier | Generate | Verify | Keys |
|---|---|---|---|
| Free | 100/day | 1,000/day | 5 total |
| Starter | 1,000/day | 10,000/day | 10 total |
| Professional | 10,000/day | 100,000/day | 50 total |
| Enterprise | Unlimited | Unlimited | Unlimited |
How Rate Limits Work
Rate limits are calculated on a sliding window basis per API key:
- Daily limits reset at midnight UTC
- Per-minute limits apply to burst protection (60 requests/minute)
- Each API key has independent limits
Response Headers
Every API response includes rate limit information:
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1708300800
X-RateLimit-Window: daily
| Header | Description |
|---|---|
X-RateLimit-Limit | Total requests allowed in window |
X-RateLimit-Remaining | Requests remaining in window |
X-RateLimit-Reset | Unix timestamp when window resets |
X-RateLimit-Window | Window type: daily or minute |
Rate Limit Exceeded (429)
When you exceed rate limits, you'll receive:
HTTP/1.1 429 Too Many Requests
Retry-After: 3600
Content-Type: application/json
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Retry after 3600 seconds.",
"details": {
"limit": 1000,
"window": "daily",
"retryAfter": 3600
}
}
}
Handling Rate Limits
Exponential Backoff
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
const delay = Math.min(retryAfter * 1000, 60000) * Math.pow(2, i);
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}
Python with Backoff
import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def create_session():
session = requests.Session()
retry = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
respect_retry_after_header=True
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('https://', adapter)
return session
session = create_session()
response = session.post(
'https://api.optropic.com/api/v1/code/verify',
headers={'x-api-key': 'your_key'},
json={'url': '...'}
)
Best Practices
1. Monitor Your Usage
Check remaining requests before critical operations:
const response = await fetch(url, options);
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
if (remaining < 100) {
console.warn('Low rate limit remaining:', remaining);
// Send alert to operations team
}
2. Batch Where Possible
For bulk operations, use batch endpoints (coming soon) instead of individual requests.
3. Cache Verification Results
If the same code is scanned multiple times in quick succession, cache the result:
const verificationCache = new Map();
async function verifyWithCache(url) {
const cached = verificationCache.get(url);
if (cached && Date.now() - cached.timestamp < 60000) {
return cached.result; // Return cached result if < 1 minute old
}
const result = await verifyCode(url);
verificationCache.set(url, { result, timestamp: Date.now() });
return result;
}
4. Use Test Keys for Development
optr_test_ keys have separate rate limits from production keys. Use them during development to preserve production quota.
Increasing Limits
To increase your rate limits:
- Upgrade your plan — Higher tiers have higher limits
- Contact sales — For enterprise needs, contact us
- Request temporary increase — For product launches or events
Endpoint-Specific Limits
Some endpoints have additional restrictions:
| Endpoint | Additional Limit |
|---|---|
/keys (POST) | 10/hour (key registration) |
/keys (DELETE) | 5/hour (key revocation) |
/code/generate | Burst: 10/second |
/code/verify | Burst: 100/second |