Rate Limits

Understand how rate limiting works and how to optimize your API usage.

Overview

Rate limits protect our API from abuse and ensure fair usage for all users. Limits are applied per API key and vary based on your plan.

Limits reset automatically

Per-minute limits reset every 60 seconds. Daily limits reset at midnight UTC.

Limits by Plan

Each plan has different rate limits and quotas:

Free

Requests per minute

10

Requests per day

100

QR codes per month

50

  • Basic QR types
  • PNG format only

Pro

Requests per minute

60

Requests per day

5,000

QR codes per month

5,000

  • All QR types
  • All formats
  • Custom styling
  • Dynamic QR codes

Business

Requests per minute

300

Requests per day

50,000

QR codes per month

Unlimited

  • Everything in Pro
  • Priority support
  • Team collaboration
  • Bulk operations

Rate Limit Headers

Every API response includes headers to help you track your usage:

HeaderDescriptionExample
X-RateLimit-LimitMax requests per minute for your plan60
X-RateLimit-RemainingRequests remaining in current window45
X-RateLimit-ResetUnix timestamp when the window resets1704067200
Retry-AfterSeconds to wait (only on 429 responses)30
Example Response Headers
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1704067200

Handling Rate Limits

When you exceed the rate limit, you'll receive a 429 response. Here's how to handle it:

429 Response
{
  "success": false,
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Please retry after 30 seconds.",
    "details": {
      "retryAfter": 30
    }
  }
}

Implementing Exponential Backoff

Use exponential backoff with jitter for the most resilient implementation:

JavaScript
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.ok) {
      return response.json();
    }

    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After');
      const waitTime = retryAfter
        ? parseInt(retryAfter, 10) * 1000
        : Math.min(1000 * Math.pow(2, attempt) + Math.random() * 1000, 60000);

      console.log(`Rate limited. Waiting ${waitTime}ms before retry...`);
      await new Promise(resolve => setTimeout(resolve, waitTime));
      continue;
    }

    // Non-retryable error
    const error = await response.json();
    throw new Error(error.error?.message || 'Request failed');
  }

  throw new Error('Max retries exceeded');
}

// Usage
const qrCode = await fetchWithRetry('https://quality-qr.app/api/v1/qr', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ type: 'url', content: 'https://example.com' }),
});

Best Practices

Monitor your usage

Check the X-RateLimit-Remaining header to avoid hitting limits unexpectedly.

Use bulk endpoints

When generating multiple QR codes, use the bulk endpoint to create up to 100 codes in a single request.

Cache responses

Cache generated QR codes on your end to avoid regenerating the same codes repeatedly.

Implement request queuing

Queue requests client-side and process them at a rate below your limit for smoother performance.

Avoid request bursts

Spread requests evenly over time instead of sending many at once. Bursting can trigger rate limits even if you're under the daily quota.

Need Higher Limits?

Upgrade to a higher plan for increased rate limits, or contact us for custom enterprise limits.