Rate Limits

API usage is limited based on your subscription plan to ensure fair usage and service stability.

Monthly Limits by Plan

PlanMonthly PDF LimitPrice
Starter300 PDFs€9/month
Pro3,000 PDFs€29/month
Scale15,000 PDFs€59/month
EnterpriseUnlimited€99/month

Understanding Rate Limits

Monthly Quota

The monthly quota is the total number of PDFs you can generate per billing period.

  • Resets on the 1st of each month at 00:00 UTC
  • Unused quota does not roll over
  • Counted per successful PDF generation

Rate Limiting

Rate limits prevent abuse and ensure service availability for all users.

  • Measured per minute
  • Based on API key
  • Returns 429 Too Many Requests when exceeded

Checking Your Usage

Dashboard

View your current usage in the Dashboard:

  • Current month's usage
  • Remaining quota
  • Usage history

Response Headers

Each API response includes usage information:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1704067200
HeaderDescription
X-RateLimit-LimitMaximum requests per minute
X-RateLimit-RemainingRemaining requests in the current minute
X-RateLimit-ResetUnix timestamp when the rate limit resets

Rate Limit Errors

403 Forbidden (Quota Exceeded)

Returned when you've used all your monthly quota.

{
  "error": "Monthly quota exceeded. Upgrade your plan to continue.",
  "code": "QUOTA_EXCEEDED",
  "status": 403
}

Solution: Upgrade your plan or wait for the monthly reset.

429 Too Many Requests

Returned when you exceed the per-minute rate limit.

{
  "error": "Rate limit exceeded. Try again in 60 seconds.",
  "code": "RATE_LIMITED",
  "status": 429,
  "retryAfter": 60
}

Solution: Implement backoff and retry logic.

Handling Rate Limits

Implement Exponential Backoff

async function generateWithBackoff(templateId, variables, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await generatePDF(templateId, variables);
    } catch (error) {
      if (error.status === 429 && attempt < maxRetries - 1) {
        const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
        await sleep(delay);
        continue;
      }
      throw error;
    }
  }
}

Queue Requests

For high-volume applications, implement a request queue:

class PDFQueue {
  constructor(rateLimit = 60) {
    this.queue = [];
    this.processing = false;
    this.interval = (60 / rateLimit) * 1000; // ms between requests
  }

  async add(templateId, variables) {
    return new Promise((resolve, reject) => {
      this.queue.push({ templateId, variables, resolve, reject });
      this.process();
    });
  }

  async process() {
    if (this.processing || this.queue.length === 0) return;
    this.processing = true;

    while (this.queue.length > 0) {
      const { templateId, variables, resolve, reject } = this.queue.shift();
      try {
        const result = await generatePDF(templateId, variables);
        resolve(result);
      } catch (error) {
        reject(error);
      }
      await sleep(this.interval);
    }

    this.processing = false;
  }
}

Monitor Usage

async function generateWithMonitoring(templateId, variables) {
  const response = await fetch(url, options);

  // Log usage information
  const remaining = response.headers.get('X-RateLimit-Remaining');
  const limit = response.headers.get('X-RateLimit-Limit');

  console.log(`Rate limit: ${remaining}/${limit} remaining`);

  if (parseInt(remaining) < 10) {
    console.warn('Approaching rate limit!');
  }

  return response.json();
}

Upgrading Your Plan

If you regularly hit your limits:

  1. Go to Billing in the dashboard
  2. Select a higher tier plan
  3. Your new limits apply immediately

Enterprise Plans

Need higher limits or custom solutions? Contact us to discuss enterprise options.

Best Practices

1. Cache When Possible

Don't regenerate PDFs if the content hasn't changed. Cache generated PDF URLs.

2. Batch Processing

If you need to generate many PDFs, spread them over time rather than all at once.

3. Monitor Proactively

Set up alerts when you approach your monthly quota (e.g., at 80% usage).

4. Use Webhooks

For high-volume use cases, consider implementing webhooks instead of polling.

5. Optimize Templates

Simpler templates generate faster, allowing you to make more requests within rate limits.