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

# AuditRails Rate Limits: Quotas and Throttling Rules

> How AuditRails rate limiting works, which limits apply to your plan and key type, how to handle 429 responses, and tips for high-throughput logging.

AuditRails enforces rate limits to ensure fair, reliable service for all tenants. All limits use a **fixed-window algorithm** with a one-second window — the counter resets at the start of each new second. Three independent limits are evaluated in order on every inbound request, and the first one exceeded produces a `429` response. Understanding how these layers work together helps you design your integration to stay well within limits and handle throttling gracefully when it does occur.

## How the Three Limit Layers Work

Each request passes through the following checks in order. If any check fails, the request is rejected immediately and subsequent checks are not evaluated.

### 1. Per-IP Limit

**100 requests per second**, evaluated before authentication. This limit applies universally to all callers regardless of plan, key type, or tenant, and cannot be increased.

* **Error code:** `rate/ip_limit_exceeded`
* **When it triggers:** More than 100 requests originate from the same IP address within a single second.
* **How to resolve:** Distribute outbound requests across multiple IPs, or reduce your per-IP send rate.

### 2. Per-Plan Limit (Live Keys)

Applies to all requests authenticated with a live key (`at_live_...`). The limit is set at the plan level and is admin-configurable — your current effective limit is always shown on the **Dashboard → Billing** page.

| Plan              | Default Rate Limit |
| ----------------- | ------------------ |
| Starter Trails    | 1,000 req/s        |
| Framework Trails  | 1,000 req/s        |
| Compliance Trails | 1,000 req/s        |

* **Error code:** `rate/limit_exceeded`
* **When it triggers:** Your project exceeds its plan's request rate within a single second.
* **How to resolve:** Wait the number of seconds specified in the `Retry-After` response header, then retry. If you consistently hit this limit, consider upgrading your plan or contacting sales for a custom limit.

### 3. Test-Key Limit

Applies exclusively to requests authenticated with a test key (`at_test_...`). Test keys draw from a separate pool and are intentionally capped at a lower rate to encourage proper use of live keys in production environments.

**60 requests per second** per test key.

* **Error code:** `rate/test_limit_exceeded`
* **When it triggers:** More than 60 requests are made with a test key within a single second.
* **How to resolve:** Switch to a live key (`at_live_...`) for all production and load-testing workloads.

<Warning>
  Never use test keys (`at_test_...`) in production. Test key events are stored separately, are not included in compliance exports, and are subject to lower rate and retention limits. Use live keys for all production logging.
</Warning>

***

## Monthly Event Quotas

In addition to per-second rate limits, each plan includes a monthly event quota. Batch ingestion counts each *event* toward the quota — not each *request*.

| Plan              | Monthly Event Quota      |
| ----------------- | ------------------------ |
| Starter Trails    | 250,000 events / month   |
| Framework Trails  | 1,000,000 events / month |
| Compliance Trails | Unlimited                |

<Info>
  Your current monthly usage and remaining quota are visible on the **Dashboard → Billing** page. You will receive email notifications at 80% and 100% of your monthly quota.
</Info>

***

## Batch Requests and Rate Limit Counting

A batch request (up to 100 events) counts as **one request** against all rate limit counters, regardless of how many events it contains. This makes batching the most efficient way to ingest high volumes of events without exhausting your rate limit.

| Ingestion method                              | Rate limit cost | Monthly quota cost |
| --------------------------------------------- | --------------- | ------------------ |
| Single event (`POST /v1/events`)              | 1 request       | 1 event            |
| Batch of 100 events (`POST /v1/events/batch`) | 1 request       | 100 events         |

<Tip>
  Use the SDK's `log()` method for all production logging. It automatically batches events in the background, respects rate limits, and retries with exponential backoff — giving you up to 100× the effective throughput compared to logging events one at a time with `logDirect()`.
</Tip>

***

## 429 Response Format

When any rate limit is exceeded, AuditRails returns an HTTP `429 Too Many Requests` response with a `Retry-After` header indicating the number of seconds to wait before retrying.

```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 1
```

```json theme={null}
{
  "error": {
    "code": "rate/limit_exceeded",
    "message": "Starter Trails plan: 1000 req/s limit exceeded. Retry after 1 second.",
    "request_id": "req_01HX...",
    "doc_url": "https://docs.auditrails.io/reference/error-codes"
  }
}
```

<Note>
  AuditRails does **not** include `X-RateLimit-*` headers (e.g. `X-RateLimit-Remaining`) on successful responses. Rate limit state is only communicated via `Retry-After` on `429` responses. Use the **Dashboard → Billing** page to monitor usage trends over time.
</Note>

***

## SDK Behavior

The AuditRails SDK handles rate limiting automatically, with different behavior depending on which method you use:

| Method        | Rate limit behavior                                                                                                                        |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `log()`       | Events are auto-batched. Rate limit errors are retried transparently with exponential backoff. No exception is raised in your application. |
| `logDirect()` | Sends a single event synchronously. Rate limit errors are surfaced as exceptions and must be handled by your code.                         |

For most production use cases, `log()` is the correct choice. Reserve `logDirect()` for situations where you need synchronous confirmation or are implementing your own batching and retry logic.

***

## Best Practices for High-Throughput Logging

1. **Respect `Retry-After`.** Always honor the value in the `Retry-After` header. Retrying immediately after a `429` will produce another `429` and waste your quota.

2. **Implement exponential backoff.** If you are calling the API directly (not via SDK), back off exponentially on repeated `429` responses: 1 s → 2 s → 4 s → 8 s, with jitter to avoid thundering-herd problems.

3. **Use batch ingestion.** Call `log()` (SDK) or `POST /v1/events/batch` (API) to pack up to 100 events into a single request. This reduces rate limit pressure by up to 100× compared to single-event requests.

4. **Use live keys for production.** Test keys are limited to 60 req/s and are not suitable for any workload beyond integration testing and local development.

5. **Upgrade your plan for higher monthly quotas.** If you are consistently approaching your monthly event quota, upgrade to Framework Trails or Compliance Trails — both offer significantly higher or unlimited monthly capacity.

***

## Custom Rate Limits

If your use case requires a rate limit higher than your plan's default, contact the AuditRails sales team. Custom limits are available on all paid plans and are configured at the project level.

[Contact Sales →](https://auditrails.io/contact)
