# Rate limits & errors

The API enforces two independent limits per key: a **monthly quota** per action and a **per-minute rate limit**.

## Quotas by plan

| Plan | Generate / mo | Validate / mo | Rate limit | llms-full |
| --- | --- | --- | --- | --- |
| Free | 25 | 2,000 | 10 / min | — |
| Starter | 400 | 20,000 | 30 / min | ✓ |
| Pro | 1,500 | 100,000 | 60 / min | ✓ |
| Business | Custom | Custom | Custom | ✓ |

Quotas reset at the start of each UTC month. Usage is visible per key in **[Account → API keys](/account/api)**.

## Rate-limit headers

Successful responses include your remaining monthly allowance for that action:

```text
X-RateLimit-Limit: 400
X-RateLimit-Remaining: 388
```

When the **per-minute** burst limit is hit, the response is `429` with a `Retry-After`:

```text
Retry-After: 60
```

## Error format

Errors are JSON with a `statusCode` and a human-readable `message`:

```json
{ "statusCode": 429, "message": "Monthly 'generate' limit reached for the Starter plan (400). Upgrade your plan to raise it." }
```

| Status | Meaning | What to do |
| --- | --- | --- |
| `400` | Bad request (missing/invalid field) | Fix the request body. |
| `401` | Missing or invalid API key | Check the key and header. |
| `403` | Feature not on your plan | Upgrade, or change the request. |
| `413` | Payload too large (validate `content` > 500 KB) | Send a smaller file. |
| `429` | Quota or rate limit reached | Back off (`Retry-After`) or upgrade. |
| `5xx` | Upstream/site error | Retry; if it persists, the target site may be blocking access. |

::callout{type="tip"}
Read `X-RateLimit-Remaining` and slow down before you hit `429`. For bursts, honour `Retry-After` rather than retrying immediately.
::
