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

# Rate limiting

> Understand API rate limits and how to handle them.

The Leonar API enforces rate limits to ensure fair usage and platform stability.

## Limits

| Metric            | Limit             |
| ----------------- | ----------------- |
| Requests per hour | 2,000 per API key |

<Note>
  **Exception — `POST /sourcing/advanced/profiles/search`** is **not** subject to
  the global per-API-key rate limit. Throughput on that endpoint is gated solely
  by the workspace's sourcing credit balance (one credit consumed per profile
  returned). Standard `X-RateLimit-*` response headers are not returned for
  that endpoint.
</Note>

## Response headers

Every API response includes rate limit headers:

| Header                  | Description                              |
| ----------------------- | ---------------------------------------- |
| `X-RateLimit-Limit`     | Maximum requests allowed per hour        |
| `X-RateLimit-Remaining` | Remaining requests in the current window |
| `X-RateLimit-Reset`     | Unix timestamp when the limit resets     |

## Handling rate limits

When you exceed the limit, the API returns a `429` status code:

```json theme={null}
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Limit: 2000 requests per hour."
  }
}
```

**Best practices:**

1. Check `X-RateLimit-Remaining` before making requests
2. Use exponential backoff when you receive a `429`
3. Cache responses when possible to reduce API calls
4. Use bulk endpoints (e.g., sequence enrollment accepts multiple contact IDs)

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

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

        if response.status_code == 429:
            reset_time = int(response.headers.get("X-RateLimit-Reset", 0))
            wait = max(reset_time - time.time(), 2 ** attempt)
            time.sleep(wait)
            continue

        return response

    raise Exception("Rate limit exceeded after retries")
```
