# Rate limits and quotas

Two limits apply: requests a second for each key, and calls a month for your account, shared by all its keys. Every lookup response reports both in its headers. Calls over the quota are blocked, never billed.

Source: https://inplan.io/docs/rate-limits · Updated 2026-10-30

## Limits by plan

| Plan | Requests a second | Calls a month | Batch pairs |
| --- | --- | --- | --- |
| Free | 2 | 500 | Not included |
| Builder | 10 | 25,000 | 100 |
| Growth | 25 | 150,000 | 100 |
| Scale | Set with you | Set with you | 100 |

Short bursts above the per-second rate are allowed. The `RateLimit-Policy` header states the rate and the burst size of your key. Prices are on the [pricing page](https://inplan.io/pricing).

## Headers

Every response that passes the key and plan checks carries these headers. A `401` or `403 plan_upgrade_required` response carries only `X-Request-Id`.

| Header | Meaning |
| --- | --- |
| `RateLimit-Limit` | Requests a second this key allows. |
| `RateLimit-Remaining` | Requests you can send right now before the limit applies. |
| `RateLimit-Reset` | Seconds until the allowance refills (at least 1). |
| `RateLimit-Policy` | The rate and burst size, for example `10;w=1;burst=20`. |
| `X-Quota-Limit` | Calls included this month for your account (all its keys share them). |
| `X-Quota-Remaining` | Calls your account has left this month. |
| `X-Quota-Reset` | Unix time of the monthly reset: the 1st of next month, 00:00 UTC. |
| `X-Request-Id` | Unique to this request. Same as `request_id` in the body. |
| `Retry-After` | On `429` and `503` only: seconds to wait before you retry. |

## What counts as a call

- Each request to a lookup endpoint is one call.
- Each accepted item in a batch is one call, so a batch of 100 valid pairs uses 100 calls. Items that fail validation cost nothing, and a batch refused as a whole (more than 100 items or an invalid body) costs nothing.
- A request that reaches the lookup counts even when it answers `400` or `404`.
- These do not count: `GET /v1/status`, a request rejected for its key (`401`) or plan (`403 plan_upgrade_required`), a request over a limit (`429`), and a server error (`5xx`).

## When you hit the per-second limit

The API answers `429` with the type `rate_limited` and a `Retry-After` header. Wait that many seconds, then retry. Spread steady traffic below `RateLimit-Limit` instead of sending it in bursts.

Response (429 Too Many Requests · application/problem+json):

```http
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json; charset=utf-8
Retry-After: 1
RateLimit-Limit: 2
RateLimit-Remaining: 0
RateLimit-Reset: 1
RateLimit-Policy: 2;w=1;burst=5
X-Request-Id: req_TrHd8LO8HNbLoZ_D
```

```json
{
  "type": "rate_limited",
  "title": "Too many requests",
  "status": 429,
  "detail": "This key allows 2 requests per second.",
  "instance": "/v1/coverage",
  "request_id": "req_TrHd8LO8HNbLoZ_D",
  "docs": "https://inplan.io/docs/errors#rate_limited"
}
```

## When you use the monthly quota

The API answers `429` with the type `quota_exceeded` until the quota resets on the 1st of the month, UTC. The body adds `quota`, `used`, `cost` and `resets_at`, and `Retry-After` holds the seconds until the reset. We never bill calls over the quota. To keep going sooner, move to a larger plan.

A batch that needs more calls than you have left is refused as a whole, so nothing in it is answered or counted.

## When the API is busy

Under heavy load the API answers `503` with the type `busy`, and a lookup that takes too long answers `503 timeout`. Both carry `Retry-After`. They never count against your quota. Retry after the delay, with backoff if it repeats.
