> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useqrkit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate Limiting

> Rate limits by plan, response headers, and handling 429 errors

## Rate limits

Rate limits restrict how many requests you can make per minute to prevent abuse and ensure fair usage.

| Plan    | Requests per minute |
| ------- | ------------------: |
| Free    |                   — |
| Starter |                  20 |
| Plus    |                  60 |
| Pro     |                 120 |
| Ultra   |                 300 |
| Agency  |                 300 |

## Monthly quotas

Monthly quotas cap the total number of API requests per calendar month.

| Plan    | API access    | Requests per month |
| ------- | ------------- | -----------------: |
| Free    | Not available |                  — |
| Starter | Yes           |                500 |
| Plus    | Yes           |              3,000 |
| Pro     | Yes           |             10,000 |
| Ultra   | Yes           |             50,000 |
| Agency  | Yes           |             50,000 |

<Warning>
  The API is not available on the Free plan. Upgrade to Starter or above to access the API.
</Warning>

<Info>
  Both the per-minute limit and the monthly quota apply to your whole workspace — creating extra keys does not increase either. A workspace can hold at most 10 active API keys. If you need higher limits, [contact us](mailto:support@useqrkit.com) about a custom plan.
</Info>

## Response headers

Every API response includes rate limit headers:

| Header                  | Description                                               |
| ----------------------- | --------------------------------------------------------- |
| `X-RateLimit-Limit`     | Maximum requests allowed per window                       |
| `X-RateLimit-Remaining` | Requests remaining in current window                      |
| `X-RateLimit-Reset`     | Unix timestamp when the window resets                     |
| `Retry-After`           | Seconds to wait before retrying (only on `429` responses) |

Example headers:

```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1705312800
```

## Handling 429 errors

When you exceed the rate limit, the API returns a `429` status with a `Retry-After` header:

```json theme={null}
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Retry after 30 seconds.",
    "doc_url": "https://docs.useqrkit.com/errors#rate_limit_exceeded",
    "request_id": "req_abc123"
  }
}
```

### Retry with backoff

<CodeGroup>
  ```python Python theme={null}
  import time
  import requests

  def make_request(url, headers, json=None):
      for attempt in range(5):
          response = requests.post(url, headers=headers, json=json)

          if response.status_code != 429:
              return response

          retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
          print(f"Rate limited. Retrying in {retry_after}s...")
          time.sleep(retry_after)

      return response
  ```

  ```javascript Node.js theme={null}
  async function makeRequest(url, options) {
    for (let attempt = 0; attempt < 5; attempt++) {
      const response = await fetch(url, options);

      if (response.status !== 429) {
        return response;
      }

      const retryAfter = parseInt(response.headers.get("Retry-After") || 2 ** attempt);
      console.log(`Rate limited. Retrying in ${retryAfter}s...`);
      await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
    }
  }
  ```
</CodeGroup>

## Best practices

<Steps>
  <Step title="Check remaining quota">
    Monitor `X-RateLimit-Remaining` to avoid hitting the limit.
  </Step>

  <Step title="Use exponential backoff">
    When retrying after a 429, use the `Retry-After` header value or exponential backoff.
  </Step>

  <Step title="Use batch creation">
    Use the [Batches API](/api-reference/batches/create) to create up to 1,000 QR codes in a single request instead of making individual calls.
  </Step>

  <Step title="Cache responses">
    Cache `GET` responses to reduce unnecessary API calls.
  </Step>
</Steps>
