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

# Rate Limit

## Overview

Our API implements rate limiting to ensure fair usage and maintain service stability for all users. Rate limits are measured in **queries** (not HTTP requests — see [How Queries Are Counted](#how-queries-are-counted) below). When you exceed the rate limit, you'll receive a `429 Too Many Requests` response with helpful headers to guide your retry strategy.

## Rate Limits

* **Default Rate Limit**: 200 queries per minute per API key
* **Rate Limit Window**: 60-second sliding window

## How Queries Are Counted

Rate limits are counted in **queries**, not in HTTP requests. The number of queries a single API call consumes depends on the endpoint type:

* **Single-entity endpoints**: one request equals one query.
* **Bulk / batch endpoints** (such as the enrichment and match endpoints): each row (entity) in the request payload counts as a separate query. A single HTTP request that submits 50 entities consumes **50 queries** against your limit — not 1.

<Warning>
  A single API call is **not** always a single query. When you send a batch of 50 entities to a bulk endpoint, that one request counts as **50 queries** toward your per-minute limit.
</Warning>

### Examples

| API call                        | Endpoint type | Entities in payload | Queries counted |
| :------------------------------ | :------------ | :------------------ | :-------------- |
| Enrich a batch of 50 businesses | Bulk          | 50                  | 50              |
| Match a batch of 10 prospects   | Bulk          | 10                  | 10              |
| Enrich a single business        | Single        | 1                   | 1               |

Because each entity is a query, the `X-RateLimit-Remaining` header decrements by the number of entities in your request — not by 1 per call. Size your batches accordingly to stay within the 200-queries-per-minute limit.

### Rate Limit Headers

When making requests to our API, the following headers are included in every response to help you track your usage:

| Header                  | Description                                                                | Example      |
| :---------------------- | :------------------------------------------------------------------------- | :----------- |
| `X-RateLimit-Limit`     | Maximum number of queries allowed in the current window                    | `200`        |
| `X-RateLimit-Remaining` | Number of queries remaining in the current window                          | `150`        |
| `X-RateLimit-Reset`     | Unix timestamp when the rate limit window resets                           | `1234567890` |
| `Retry-After`           | Number of seconds to wait before retrying (only included in 429 responses) | `60`         |

## Rate Limit Response

When you exceed the rate limit, you'll receive the following response:

```bash HTTP theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1234567890
Content-Type: application/json

{
  "error": "rate_limit_exceeded",
  "message": "API rate limit exceeded. Please retry after 60 seconds.",
  "retry_after": 60
}
```

## Implementing Retry Logic

### Best Practices

1. **Always check for 429 responses** and implement exponential backoff
2. **Respect the Retry-After header** - this tells you the minimum time to wait
3. **Monitor your usage** using the `X-RateLimit-Remaining` header
4. **Account for batch size** - remember each entity in a bulk request counts as a query
5. **Implement preemptive throttling** when `X-RateLimit-Remaining` is low

### Example Implementation

<CodeGroup>
  ```python Python expandable theme={null}
  import time
  import requests
  from typing import Dict, Any, Optional

  class APIClient:
      def __init__(self, api_key: str, base_url: str):
          self.api_key = api_key
          self.base_url = base_url
          self.session = requests.Session()
          self.session.headers.update({
              'Authorization': f'Bearer {api_key}'
          })

      def make_request(
          self,
          endpoint: str,
          method: str = 'GET',
          max_retries: int = 3,
          **kwargs
      ) -> Dict[str, Any]:
          """Make an API request with automatic retry logic."""
          url = f"{self.base_url}{endpoint}"
          retry_count = 0

          while retry_count < max_retries:
              try:
                  response = self.session.request(method, url, **kwargs)

                  # Log rate limit information
                  remaining = response.headers.get('X-RateLimit-Remaining')
                  if remaining:
                      print(f"Rate Limit Remaining: {remaining}")

                  response.raise_for_status()
                  return response.json()

              except requests.exceptions.HTTPError as e:
                  if e.response.status_code == 429:
                      retry_count += 1

                      # Get retry delay from header
                      retry_after = e.response.headers.get('Retry-After')
                      if retry_after:
                          delay = int(retry_after)
                      else:
                          # Exponential backoff with jitter
                          delay = min(2 ** retry_count, 60)

                      print(f"Rate limit hit. Retrying after {delay} seconds...")

                      if retry_count < max_retries:
                          time.sleep(delay)
                          continue

                  raise

          raise Exception("Max retries exceeded")

  # Usage example
  client = APIClient('your-api-key', 'https://api.example.com')

  try:
      data = client.make_request('/users', method='GET')
      print('Data:', data)
  except Exception as e:
      print(f'Error: {e}')
  ```

  ```javascript JavaScript expandable theme={null}
  const axios = require('axios');

  class APIClient {
    constructor(apiKey, baseURL) {
      this.apiKey = apiKey;
      this.baseURL = baseURL;
    }

    async makeRequest(endpoint, options = {}) {
      const maxRetries = 3;
      let retryCount = 0;

      while (retryCount < maxRetries) {
        try {
          const response = await axios({
            method: options.method || 'GET',
            url: `${this.baseURL}${endpoint}`,
            headers: {
              'Authorization': `Bearer ${this.apiKey}`,
              ...options.headers
            },
            ...options
          });

          // Log rate limit info
          console.log(`Rate Limit Remaining: ${response.headers['x-ratelimit-remaining']}`);

          return response.data;
        } catch (error) {
          if (error.response && error.response.status === 429) {
            retryCount++;

            // Get retry delay from header or use exponential backoff
            const retryAfter = error.response.headers['retry-after'];
            const delay = retryAfter
              ? parseInt(retryAfter) * 1000
              : Math.min(1000 * Math.pow(2, retryCount), 60000);

            console.log(`Rate limit hit. Retrying after ${delay/1000} seconds...`);

            if (retryCount < maxRetries) {
              await this.sleep(delay);
              continue;
            }
          }
          throw error;
        }
      }

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

    sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
  }

  // Usage example
  const client = new APIClient('your-api-key', 'https://api.example.com');

  async function fetchData() {
    try {
      const data = await client.makeRequest('/users', {
        method: 'GET'
      });
      console.log('Data:', data);
    } catch (error) {
      console.error('Error:', error.message);
    }
  }
  ```
</CodeGroup>

## Monitoring Rate Limits

### Preemptive Rate Limiting

To avoid hitting rate limits, monitor the `X-RateLimit-Remaining` header and implement throttling. Remember that `X-RateLimit-Remaining` reflects queries remaining, so a single bulk request can consume many at once:

```javascript JavaScript theme={null}
// JavaScript example
if (response.headers['x-ratelimit-remaining'] < 10) {
  // Slow down requests when approaching limit
  await sleep(1000); // Wait 1 second between requests
}
```

## Frequently Asked Questions

<AccordionGroup>
  <Accordion title="What happens if I consistently hit rate limits?">
    Repeated rate limit violations may result in temporary suspension of API access. Implement proper retry logic and consider upgrading your plan if you need higher limits.
  </Accordion>

  <Accordion title="How is the rate limit window calculated?">
    We use a sliding window approach that tracks queries over the past 60 seconds. Each query timestamp is recorded, and queries older than 60 seconds are removed from the count.
  </Accordion>

  <Accordion title="How are queries counted for bulk or batch endpoints?">
    The rate limit counts queries, not HTTP requests. For bulk and batch endpoints (such as enrichment and match), every row (entity) in your request payload counts as one query. For example, a single request that submits 50 entities to a batch endpoint consumes 50 queries from your per-minute limit — not 1. Single-entity endpoints count as one query per request.
  </Accordion>

  <Accordion title="Are rate limits applied per API key or per IP address?">
    Rate limits are applied per API key. Each API key has its own independent rate limit counter.
  </Accordion>

  <Accordion title="Do different endpoints have different rate limits?">
    Currently, all endpoints share the same rate limit of 200 queries per minute. Keep in mind that bulk and batch endpoints count each entity in the payload as a separate query, so a single call to those endpoints can consume multiple queries. Some endpoints may have additional specific limits which will be documented separately.
  </Accordion>
</AccordionGroup>
