API ReferenceRate Limits

Rate Limits

doczap implements rate limiting to ensure fair usage and maintain service quality for all users.

Plan Limits

Rate limits by plan:

PlanPDF Generations/moTest Requests/DayRate LimitWebhooks
Free100101 req/60s1
Pro2,000103 req/s5
Scale15,000105 req/s20

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
HeaderDescription
X-RateLimit-LimitTotal monthly PDF generations allowed
X-RateLimit-RemainingPDF generations remaining this month
X-RateLimit-ResetUnix timestamp when monthly limit resets
X-RateLimit-PerSecondRequests allowed per second
X-RateLimit-BurstMaximum 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

CodeDescriptionSolution
monthly_limit_exceededMonthly PDF generation limit reachedUpgrade plan
test_limit_exceededDaily test limit reached (10/day)Wait until midnight UTC
rate_limit_exceededPer-second rate limit exceededImplement backoff
webhook_limit_exceededWebhook limit for plan reachedUpgrade 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

  1. Monitor Usage: Check dashboard regularly
  2. Use Test Mode: During development to save quota
  3. Implement Caching: Avoid regenerating identical PDFs
  4. Batch with Async: Use webhooks for high-volume processing
  5. 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.