# Rate limits & quotas

{/* // LIMITS THAT DON'T PUNISH FAN-OUT */}

Postern publishes its limits and designs them **not to punish fan-out** across many mailboxes — an
agent fleet creating and using lots of inboxes is the expected shape, not an attack. Every limit
surfaces in a response header so your agent can back off cleanly instead of guessing.

## The limits, at a glance

| Limit | Default | Where it lives |
|---|---|---|
| Mailboxes per enrollment key | `max_mailboxes` (set at mint) | Enrollment key |
| Daily send per mailbox | ramps 5–10/day → 30–50/day over weeks | Per mailbox |
| Complaint rate (platform) | kept `<0.1%` (hard ceiling `<0.3%`) | Platform |
| Request rate | published; fan-out-friendly | Per agent key |
| `wait_for_email` max block | `300s` (server `POSTERN_MAX_WAIT_MS`) | Per request |

## Mailbox quota

An enrollment key can mint at most `max_mailboxes` mailboxes over its lifetime. The counter
(`used_count`) is **server-enforced**, so a cloned key can't exceed the cap. At the cap, create returns:

```json
// 409 Conflict
{ "error": { "code": "enrollment_token_exhausted",
  "message": "This enrollment key is exhausted — it minted its max of 5 mailboxes. Issue a new key." } }
```

Deleting a mailbox does **not** refund a slot — `used_count` is lifetime mints, which is what bounds a
leaked key. See [Enrollment tokens & scopes](https://docs.agents.mszazu.com/concepts/enrollment-tokens/).

## Ramping send caps

Each mailbox's daily send cap ramps as it proves itself — roughly 5–10/day at first, climbing to
30–50/day over weeks. [Karma](https://docs.agents.mszazu.com/concepts/deliverability-and-karma/) modulates the ramp: replies earn
headroom, one-directional spray gets throttled. Over the cap returns `429` with `Retry-After`.

## Request rate limits

Per-agent-key request limits are published and tuned so a fleet creating and reading many mailboxes
isn't penalized for normal fan-out. When you hit a limit:

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 2
X-Postern-Request-Id: req_7Yc2
```

```json
{ "error": { "code": "rate_limited", "message": "Slow down — retry after 2s." } }
```
**Let the SDK handle backoff:** The TypeScript SDK retries idempotent requests (`GET` / `DELETE`) on `429` / `5xx` / network errors
  with jittered backoff that honors `Retry-After`. For `POST`s, pass `client_id` (create) or
  `idempotency_key` (send/reply) so a retry can't duplicate. See [Errors](https://docs.agents.mszazu.com/api/errors/).

## Headers to read

| Header | On | Meaning |
|---|---|---|
| `Retry-After` | `429` | Seconds to wait before retrying. |
| `X-Postern-Request-Id` | every response | Correlation id for support. |
| `PAYMENT-REQUIRED` | `402` | x402 challenge for paid actions. |

## Quotas vs. caps — both stack

Two independent limits apply to sending:

1. the enrollment key's **mailbox quota** (how many inboxes exist), and
2. each mailbox's **daily send cap** (how much each one can send).

An agent can hit either. Read the `error.code` to tell them apart: `enrollment_token_exhausted` (out
of mailboxes) vs `rate_limited` (over a send/request cap). distinct codes

## Next

- [Deliverability & karma](https://docs.agents.mszazu.com/concepts/deliverability-and-karma/) — how the ramp and karma interact.
- [x402 test mode](https://docs.agents.mszazu.com/payments/x402-test-mode/) — the economic limit on bulk provisioning.
- [Self-host](https://docs.agents.mszazu.com/operating/self-host/) — running Postern with your own limits.