# Rate limits and quotas

Several independent limits can affect one request. Read the status, problem `code`, details, and
`Retry-After` header instead of inferring the cause from a single counter.

## Limit summary

| Limit | Unit | Scope |
|---|---|---|
| Enrollment creation limit | Lifetime successful inbox creates | Enrollment key, stored as `max_mailboxes` and `used_count` |
| Daily send limit | Recipients delivered in a rolling 24-hour window | Inbox |
| Request rate | API requests in the configured window | Agent key or route |
| Project and inbox capacity | Active resources | Billing plan and project |
| Domain purchase authority | Money, domain count, extension, premium status, and cadence | Matching organization, project, and agent purchase limits |
| Wait budget | Seconds or milliseconds per long-poll | Request and server configuration |

## Lifetime inbox creation

An enrollment key stops creating inboxes after `used_count` reaches `max_mailboxes`. The server owns
the counter, so copying the key does not create another allowance. Deleting an inbox does not refund a
lifetime slot.

The wire fields retain **mailbox** for compatibility. User-facing instructions and console labels use
**inbox**.

Project and plan capacity are separate. A project may reach its active inbox cap before the enrollment
key reaches its own lifetime limit.

## Rolling recipient accounting

The default inbox limit is 75 recipients per rolling 24 hours. One message sent to three recipients
uses three units. The effective `daily_send_limit` may be set from 1 to 10,000 with
`mailbox:quota`; `0` on an enrollment key means the organization's default should apply.

The limit is checked when a message is submitted and again before reviewed mail is released. The
second check prevents a queued message from bypassing a limit that changed while it waited. Capacity is
counted once, only when delivery occurs.

- A queued review has not consumed capacity.
- `intent_required`, suppression, and contact-list rejections consume none.
- An over-limit response includes `429` and `Retry-After`.

## Request throttles

When an API throttle applies, the response uses `429 Too Many Requests` and includes `Retry-After` in
seconds. Back off with jitter and preserve the request's idempotency value when retrying the same
mutation.

The TypeScript SDK retries eligible idempotent requests for transient failures. It does not make an
unsafe mutation idempotent by guessing. For send, reply, and forward, pass `idempotency_key`; for MCP
outbound mutations, pass `client_id`.

## Wait limits

REST and the TypeScript SDK default `wait_for_email` to 300 seconds and cap it at 600 seconds. MCP
defaults to 120 seconds and also caps at 600 seconds, subject to the packaged server's configured
maximum. Client and proxy read timeouts must exceed the requested wait.

Review-event long-polls have their own shorter bounded interval. Follow each tool or endpoint's
published field rather than reusing the email wait budget.

## Plan and project capacity

Plan limits apply to projects, active inboxes, and customer-controlled domains. They are checked in the
same authorization path as resource creation. No credential permission bypasses plan capacity.

An agent can request a plan change with `commerce:request`, but cannot approve it. Downgrades that do
not fit the current resource count remain pending or blocked and never delete resources automatically.

## Purchase limits

Domain purchase requests combine plan capacity with every matching organization, project, and agent
purchase limit. Controls may restrict:

- a one-time, weekly, monthly, quarterly, or annual budget;
- maximum amount per purchase;
- maximum domains;
- allowed extensions;
- premium-domain authority.

The most restrictive matching result wins. Budget reservations prevent concurrent requests from
overspending the same allowance. Unused recurring budget does not roll over.
**Permission is not approval:** `commerce:request` lets an agent quote and create a durable request. It does not authorize a charge.
  A signed-in human or a bounded purchase limit created by a human must authorize the exact request.

## Handle failures by code

| Code or status | Meaning | Response |
|---|---|---|
| `quota_exceeded` | A lifetime, active-resource, or recipient quota blocks the request | Read the detail and current limit; do not retry unchanged |
| `rate_limited` | Request rate is too high | Wait for `Retry-After`, then retry with jitter |
| `intent_required` | Review policy requires reviewer context | Add `intent.summary`; nothing was sent or queued |
| `recipient_suppressed` | At least one recipient cannot receive this message | Remove or resolve the blocked recipient before retrying |
| `awaiting_human_approval` | A commerce request needs a person | Surface the approval URL and poll at the recommended interval |

## Next

- [Deliverability and limits](https://docs.extrovert.dev/concepts/deliverability-and-limits/)
- [Enrollment keys and permissions](https://docs.extrovert.dev/concepts/enrollment-tokens/)
- [Purchase approvals for agents](https://docs.extrovert.dev/concepts/purchase-approvals-for-agents/)
- [API errors](https://docs.extrovert.dev/api/errors/)