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

# Rate Limits

> Sliding window rate limiting, retry strategy, and best practices.

## Overview

The Partner API enforces per-partner rate limiting using a **sliding window** algorithm. Each API Key has an independent rate limit counter.

<Note>
  Rate limiting is only active when a `rateLimit` value has been configured for your API Key. If no limit is configured, requests are not throttled. Contact the CleanLife integration team to confirm your rate limit quota.
</Note>

***

## How It Works

1. Every authenticated request counts toward your API Key's limit within the current window.
2. The window is **60 seconds** (sliding). When a new window starts, the counter resets.
3. If the counter exceeds your configured limit, the request is rejected with `429 Too Many Requests`.

***

## Rate Limit Window

| Property        | Value                                      |
| --------------- | ------------------------------------------ |
| Window type     | Sliding window                             |
| Window duration | 60 seconds                                 |
| Counter scope   | Per API Key (not per IP, not per endpoint) |

***

## Rate Limit Error

When the limit is exceeded, the API returns:

**HTTP Status:** `429 Too Many Requests`

```json theme={null}
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Partner API rate limit exceeded",
    "requestId": "a1b2c3d4-..."
  }
}
```

<Note>
  The `Retry-After` header is not currently included in the `429` response. The window is always 60 seconds, so you can safely wait 60 seconds before retrying.
</Note>

***

## Retry Behavior

When you receive a `429`, implement the following retry strategy:

1. **Stop sending requests immediately** — do not retry in a tight loop.
2. **Wait at least 60 seconds** — the full sliding window duration.
3. **Resume with reduced throughput** — spread requests evenly rather than bursting.

### Recommended Backoff

```
attempt 1: wait 60s
attempt 2: wait 90s
attempt 3: wait 120s
```

***

## Best Practices

### Spread Your Requests

Avoid sending all requests in a burst at the start of each minute. Spread them evenly across the 60-second window.

**Bad:**

```
Second 0:  50 requests → hits limit
Seconds 1–59: requests rejected
```

**Good:**

```
Evenly distribute: ~1 request/second for a 60 req/min limit
```

### Use a Queue

For high-volume operations (e.g. batch booking creation), use an internal queue in your system that dispatches requests at a controlled rate rather than sending them all simultaneously.

### Handle 429 Gracefully

Always check for the `429` status code in your HTTP response handling. Do not treat it as a fatal error — it is recoverable.

```javascript theme={null}
async function callWithRetry(fn, maxAttempts = 3) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (err.response?.status === 429 && attempt < maxAttempts) {
        const waitMs = 60_000 * attempt; // 60s, 120s, 180s
        console.warn(`Rate limited. Waiting ${waitMs}ms before retry...`);
        await new Promise(resolve => setTimeout(resolve, waitMs));
        continue;
      }
      throw err;
    }
  }
}
```

### Monitor Usage

Log every `429` response your integration receives. A sustained rate of `429` errors indicates that your request throughput is too high. Consider requesting a higher limit from the CleanLife team.

***

## Requesting a Higher Limit

If your integration requires a higher throughput, contact the CleanLife integration team with:

* Your partner ID
* Your expected peak requests per minute
* A brief description of your use case

Rate limits are configured per API Key and can be adjusted on a case-by-case basis.
