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

# Rate Limits

> Understanding API rate limits and how to handle them

# Rate Limits

The Doppel API implements rate limiting to ensure fair usage and maintain service stability. Rate limits are applied per API key.

## Rate Limit Tiers

| Tier          | Requests/Minute | Requests/Hour | Requests/Day |
| ------------- | --------------- | ------------- | ------------ |
| **Standard**  | 60              | 1,000         | 10,000       |
| **Premium**   | 300             | 5,000         | 50,000       |
| **Unlimited** | No limit        | No limit      | No limit     |

<Info>
  Contact your account manager to upgrade your rate limit tier if needed.
</Info>

## Rate Limit Headers

Every API response includes headers showing your current rate limit status:

```
X-RateLimit-Limit-Minute: 60
X-RateLimit-Remaining-Minute: 45
X-RateLimit-Limit-Hour: 1000
X-RateLimit-Remaining-Hour: 823
X-RateLimit-Limit-Day: 10000
X-RateLimit-Remaining-Day: 9156
```

## Rate Limit Exceeded Response

When you exceed a rate limit, you'll receive a `429 Too Many Requests` response:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded"
  },
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2024-01-15T10:30:00.000Z"
}
```

The response will also include a `Retry-After` header indicating how many seconds to wait:

```
Retry-After: 35
```

## Handling Rate Limits

### Basic Retry Logic

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function fetchWithRetry(url, options, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
      const response = await fetch(url, options);

      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After') || 60;
        console.log(`Rate limited. Waiting ${retryAfter}s...`);
        await new Promise(r => setTimeout(r, retryAfter * 1000));
        continue;
      }

      return response;
    }
    throw new Error('Max retries exceeded');
  }
  ```

  ```python Python theme={null}
  import time
  import requests

  def fetch_with_retry(url, headers, max_retries=3):
      for i in range(max_retries):
          response = requests.get(url, headers=headers)

          if response.status_code == 429:
              retry_after = int(response.headers.get('Retry-After', 60))
              print(f"Rate limited. Waiting {retry_after}s...")
              time.sleep(retry_after)
              continue

          return response

      raise Exception('Max retries exceeded')
  ```
</CodeGroup>

### Exponential Backoff

For more robust handling, implement exponential backoff:

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function fetchWithExponentialBackoff(url, options) {
    const maxRetries = 5;
    let delay = 1000; // Start with 1 second

    for (let i = 0; i < maxRetries; i++) {
      const response = await fetch(url, options);

      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After');
        const waitTime = retryAfter ? retryAfter * 1000 : delay;

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

        delay *= 2; // Double the delay for next retry
        continue;
      }

      return response;
    }
    throw new Error('Max retries exceeded');
  }
  ```

  ```python Python theme={null}
  import time
  import requests

  def fetch_with_exponential_backoff(url, headers):
      max_retries = 5
      delay = 1  # Start with 1 second

      for i in range(max_retries):
          response = requests.get(url, headers=headers)

          if response.status_code == 429:
              retry_after = response.headers.get('Retry-After')
              wait_time = int(retry_after) if retry_after else delay

              print(f"Rate limited. Waiting {wait_time}s...")
              time.sleep(wait_time)

              delay *= 2  # Double the delay for next retry
              continue

          return response

      raise Exception('Max retries exceeded')
  ```
</CodeGroup>

## Best Practices

### 1. Cache Responses

Cache API responses when possible to reduce the number of requests:

```javascript theme={null}
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function getClinics(apiKey) {
  const cacheKey = 'clinics';
  const cached = cache.get(cacheKey);

  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }

  const response = await fetch('https://api.getdoppel.ai/api/v1/clinics', {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });
  const data = await response.json();

  cache.set(cacheKey, { data, timestamp: Date.now() });
  return data;
}
```

### 2. Batch Requests

Instead of making many small requests, use pagination efficiently:

```bash theme={null}
# Instead of 100 requests with limit=1
curl "https://api.getdoppel.ai/api/v1/interactions?limit=1"

# Make 1 request with limit=100
curl "https://api.getdoppel.ai/api/v1/interactions?limit=100"
```

### 3. Monitor Your Usage

Check the rate limit headers in each response to monitor your usage and adjust your request patterns accordingly.

### 4. Use Webhooks (Coming Soon)

For real-time data, consider using webhooks instead of polling the API repeatedly.
