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

# Rate limits

# Rate Limits

The Benchmark Email API enforces two levels of rate limiting to ensure fair usage and platform stability: an **hourly rate limit** and a **monthly quota**.

## Hourly Rate Limit

Each account is limited to **3,600 requests per hour**, which is approximately 1 request per second sustained. This limit applies across all API keys on the account -- if you have multiple keys, they share the same hourly budget.

### Rate Limit Response Headers

Every successful API key request includes headers showing your current rate limit status:

| Header                  | Description                                            | Example      |
| ----------------------- | ------------------------------------------------------ | ------------ |
| `X-RateLimit-Limit`     | Maximum requests allowed per hour                      | `3600`       |
| `X-RateLimit-Remaining` | Requests remaining in the current hour                 | `3542`       |
| `X-RateLimit-Reset`     | Unix timestamp (seconds) when the hourly window resets | `1711828800` |

**Example response headers:**

```
HTTP/1.1 200 OK
X-RateLimit-Limit: 3600
X-RateLimit-Remaining: 3542
X-RateLimit-Reset: 1711828800
X-Monthly-Limit: 100000
X-Monthly-Remaining: 98750
Content-Type: application/json
```

## Monthly Quota

Each account has a monthly API request quota that resets at the start of each billing period. The default quota is calculated as:

```
Monthly quota = Contact limit x 10
```

For example, an account with a 10,000 contact limit has a default monthly quota of 100,000 API requests. Some plans may have a custom quota configured by the account's subscription.

### Monthly Quota Response Headers

| Header                | Description                                            | Example  |
| --------------------- | ------------------------------------------------------ | -------- |
| `X-Monthly-Limit`     | Maximum requests allowed in the current billing period | `100000` |
| `X-Monthly-Remaining` | Requests remaining in the current billing period       | `98750`  |

## Exceeding Rate Limits

When you exceed either limit, the API returns a `429 Too Many Requests` response.

### Hourly Limit Exceeded

```bash theme={null}
curl -H "X-API-Key: bme_abc123def456ghi789jkl012mno345pqr678stu90v" \
  https://api-us1-1.benchmarkemail.com/api/contact
```

**Response (429 Too Many Requests):**

```
HTTP/1.1 429 Too Many Requests
Retry-After: 45
X-RateLimit-Limit: 3600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711828800
```

```json theme={null}
{
  "errors": [
    {
      "errorType": "TooManyRequestsError",
      "message": "Rate limit exceeded. Retry after 45 seconds."
    }
  ]
}
```

The `Retry-After` header indicates how many seconds to wait before retrying.

### Monthly Quota Exceeded

```
HTTP/1.1 429 Too Many Requests
Retry-After: 86400
```

```json theme={null}
{
  "errors": [
    {
      "errorType": "TooManyRequestsError",
      "message": "Monthly API quota exceeded."
    }
  ]
}
```

When the monthly quota is exceeded, the `Retry-After` value indicates the number of seconds until the billing period resets.

## Handling Rate Limits

### Best Practices

1. **Monitor response headers.** Check `X-RateLimit-Remaining` and `X-Monthly-Remaining` on each response to stay within limits.

2. **Use exponential backoff.** When you receive a `429` response, wait for the duration specified in the `Retry-After` header. If you continue to receive `429` responses, increase the wait time exponentially:

   ```
   Wait time = min(Retry-After * 2^attempt, 300)
   ```

   Cap the maximum wait at 5 minutes (300 seconds).

3. **Spread requests evenly.** Instead of bursting 3,600 requests in a few minutes, distribute them evenly across the hour (\~1 per second).

4. **Cache responses.** If you repeatedly fetch the same data, cache it locally instead of re-requesting it from the API.

### Example: Retry Logic (pseudocode)

```
function makeRequest(url, headers):
    maxRetries = 3
    for attempt in 0..maxRetries:
        response = httpGet(url, headers)

        if response.status != 429:
            return response

        retryAfter = response.headers["Retry-After"] or 60
        waitTime = min(retryAfter * (2 ^ attempt), 300)
        sleep(waitTime)

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

## Failed Authentication Protection

To protect against key probing and brute-force attacks, the API monitors failed authentication attempts by IP address. If an IP address sends too many requests with invalid API keys, it will be temporarily blocked.

During a block, all API key requests from that IP address receive a `429 Too Many Requests` response:

```json theme={null}
{
  "errors": [
    {
      "errorType": "TooManyRequestsError",
      "message": "Too many failed authentication attempts. Please try again later."
    }
  ]
}
```

The `Retry-After` header indicates when the block will expire. To avoid triggering this protection:

* Verify your API key is correct before sending many requests.
* Do not cycle through possible key values.
* If you receive repeated `401` responses, stop and check your key rather than retrying immediately.

## Summary

| Limit                | Threshold                     | Scope                                | Reset                       |
| -------------------- | ----------------------------- | ------------------------------------ | --------------------------- |
| Hourly rate limit    | 3,600 requests/hour           | Per account (shared across all keys) | Fixed 1-hour window         |
| Monthly quota        | Contact limit x 10 (default)  | Per account                          | Billing period start        |
| Failed auth blocking | Excessive invalid keys per IP | Per IP address                       | Automatic (temporary block) |

## Next Steps

* [Errors](./errors.md) -- understand all error responses
* [Authentication](./authentication.md) -- API key setup and scopes
