Rate Limits
doczap implements rate limiting to ensure fair usage and maintain service quality for all users.
Plan Limits
Rate limits by plan:
Plan | PDF Generations/mo | Test Requests/Day | Rate Limit | Webhooks |
---|---|---|---|---|
Free | 100 | 10 | 1 req/60s | 1 |
Pro | 2,000 | 10 | 3 req/s | 5 |
Scale | 15,000 | 10 | 5 req/s | 20 |
Test requests (with isTest: true
) don’t count toward your monthly limit but are restricted to 10 per day.
Rate Limit Headers
Every API response includes rate limit information:
Monthly Generation Limits
X-RateLimit-Limit: 2000
X-RateLimit-Remaining: 1850
X-RateLimit-Reset: 1675209600
Per-Second Rate Limits
X-RateLimit-PerSecond: 3
X-RateLimit-Burst: 10
Header | Description |
---|---|
X-RateLimit-Limit | Total monthly PDF generations allowed |
X-RateLimit-Remaining | PDF generations remaining this month |
X-RateLimit-Reset | Unix timestamp when monthly limit resets |
X-RateLimit-PerSecond | Requests allowed per second |
X-RateLimit-Burst | Maximum burst capacity |
Test Mode Limits
Test mode has separate daily limits:
X-Test-Limit: 10
X-Test-Remaining: 7
X-Test-Reset: 1672444800
Test limits reset daily at 00:00 UTC.
Rate Limit Errors
When you exceed a limit, you’ll receive a 429 error:
{
"error": {
"message": "Monthly PDF generation limit exceeded",
"type": "rate_limit_error",
"code": "monthly_limit_exceeded",
"limit": 2000,
"remaining": 0,
"reset_at": "2024-02-01T00:00:00Z",
"upgrade_url": "https://app.doczap.app/billing"
}
}
Error Codes
Code | Description | Solution |
---|---|---|
monthly_limit_exceeded | Monthly PDF generation limit reached | Upgrade plan |
test_limit_exceeded | Daily test limit reached (10/day) | Wait until midnight UTC |
rate_limit_exceeded | Per-second rate limit exceeded | Implement backoff |
webhook_limit_exceeded | Webhook limit for plan reached | Upgrade plan or remove webhooks |
Handling Rate Limits
1. Monitor Usage
Check your current usage before making requests:
const response = await fetch(apiUrl, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
});
const remaining = response.headers.get('X-RateLimit-Remaining');
const limit = response.headers.get('X-RateLimit-Limit');
const percentUsed = ((limit - remaining) / limit) * 100;
if (percentUsed > 80) {
console.warn(`Usage warning: ${percentUsed.toFixed(1)}% of monthly quota used`);
}
2. Implement Backoff
When rate limited, wait before retrying:
import time
from datetime import datetime
response = requests.post(url, json=data)
if response.status_code == 429:
error = response.json()['error']
reset_time = datetime.fromisoformat(error['reset_at'])
wait_seconds = (reset_time - datetime.now()).total_seconds()
print(f"Rate limited. Waiting {wait_seconds} seconds...")
time.sleep(wait_seconds)
3. Use Test Mode Wisely
Maximize your test quota:
// Use test mode during development
const isDevelopment = process.env.NODE_ENV === 'development';
const data = {
customer: "Acme Corp",
amount: 1250.00,
...(isDevelopment && { isTest: true })
};
Best Practices
1. Batch Processing
For high-volume generation, use async mode:
// Good: Async batch processing
const promises = invoices.map(invoice =>
fetch(apiUrl, {
method: 'POST',
headers: {
...headers,
'Prefer': 'respond-async'
},
body: JSON.stringify(invoice)
})
);
const responses = await Promise.all(promises);
2. Implement Caching
Cache generated PDFs when possible:
import hashlib
def get_pdf_cached(data):
# Create cache key from data
cache_key = hashlib.md5(
json.dumps(data, sort_keys=True).encode()
).hexdigest()
# Check cache first
if cached_pdf := cache.get(cache_key):
return cached_pdf
# Generate and cache
pdf = generate_pdf(data)
cache.set(cache_key, pdf, expire=3600)
return pdf
3. Monitor Dashboard
Track usage in real-time:
- View current month usage
- Set up usage alerts
- Download usage reports
- Plan capacity ahead
Per-Second Rate Limiting
Respect per-second rate limits:
class RateLimiter {
constructor(requestsPerSecond = 1) {
this.queue = [];
this.requestsPerSecond = requestsPerSecond;
this.lastRequestTime = 0;
}
async add(task) {
const now = Date.now();
const timeSinceLastRequest = now - this.lastRequestTime;
const minInterval = 1000 / this.requestsPerSecond;
if (timeSinceLastRequest < minInterval) {
await new Promise(resolve =>
setTimeout(resolve, minInterval - timeSinceLastRequest)
);
}
this.lastRequestTime = Date.now();
return await task();
}
}
// Usage based on plan
const limiter = new RateLimiter(1/60); // Free plan: 1 req per 60s
// const limiter = new RateLimiter(3); // Pro plan: 3 req/s
// const limiter = new RateLimiter(5); // Scale plan: 5 req/s
for (const doc of documents) {
await limiter.add(() => generatePDF(doc));
}
Repeatedly hitting rate limits may result in temporary suspension. Contact support if you need higher limits.
Rate Limit Best Practices
- Monitor Usage: Check dashboard regularly
- Use Test Mode: During development to save quota
- Implement Caching: Avoid regenerating identical PDFs
- Batch with Async: Use webhooks for high-volume processing
- Plan Ahead: Upgrade before hitting limits
Enterprise Options
For high-volume needs:
- Custom rate limits
- Dedicated infrastructure
- No per-second restrictions
- Priority support
- SLA guarantees
Contact sales for Enterprise pricing.