# Limits and quotas

Limits are enforced per API ID per route and class, with a five-times account aggregate. A daily
quota applies to each call class. All counters are shared across API replicas, so a retry that
lands on another node sees the same budget.

`GET /v1/capabilities` returns the live limit object. `GET /v1/usage` returns usage for
the current period. Response headers are the per-request source of truth.

## Current limits

| Class | Sustained | Burst / aggregate | Daily quota |
| --- | ---: | ---: | ---: |
| Capabilities, manifest, usage | 120/min | 5x account aggregate | 20,000 |
| Catalogue and offer reads | 120/min | 5x account aggregate | 20,000 |
| Quote creation | 60/min | 5x account aggregate | 2,000 |
| Order creation | 30/min | 5x account aggregate | 1,000 |
| Order reads | 120/min | 5x account aggregate | 20,000 |
| Redemption | 20/min | 5x account aggregate | 1,000 |
| Wallet funding | 5/min | 5x account aggregate | 20 |
| Agent and key management | 10/min | 5x account aggregate | 50 |

Windows are fixed and aligned to the clock: per-minute windows start at the top of each UTC minute,
daily quotas reset at 00:00 UTC. A limit does not roll continuously.

`POST /v1/quotes` and `POST /v1/orders` share the same wallet and stock checks, but they
have separate counters. A quote that is rate limited creates no quote row. An order that is rate
limited creates no purchase and no debit.

## Bulk limits

| Limit | Principal | Agent default |
| --- | ---: | ---: |
| Lines per quote or order | 200 | 50 |
| Units per quote or order | 5,000 | 500 |

The principal limit is enforced by the current quote and order handlers. Agent-specific line and
unit caps are recorded on the agent identity and are part of the target contract. Until order-time
enforcement is enabled, an agent must enforce its own cap client-side and keep the principal's
mandate explicit. See [Agent payment](/docs/agent-payment).

## Response headers

Every limited response includes:

```http
RateLimit-Limit: 30
RateLimit-Remaining: 29
RateLimit-Reset: 1793251260
RateLimit-Policy: 30;w=60
```

`X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` carry the same
values for older clients. `RateLimit-Reset` is a Unix timestamp in seconds.

A `429` adds:

```http
Retry-After: 17
```

## Throttled responses

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Retry after the indicated delay.",
    "retryAfter": 17,
    "reset": "2026-11-04T03:01:00.000Z",
    "requestId": "..."
  }
}
```

A daily quota returns `429 quota_exceeded`:

```json
{
  "error": {
    "code": "quota_exceeded",
    "message": "The daily quota for this call class is exhausted.",
    "retryAfter": 48231,
    "reset": "2026-11-05T00:00:00.000Z",
    "requestId": "..."
  }
}
```

Neither response creates a quote, order, redemption or funding operation.

## Retry policy

1. Read `Retry-After`. If it is missing, use the `reset` value or a one-second start.
2. Wait at least that long. Add jitter of 10 to 30 percent to avoid synchronised retries.
3. For a mutation, reuse the same `Idempotency-Key` and the same body. Never use a new key
   for a retry of the same logical request.
4. For a read, retry with a fresh nonce.
5. Cap automatic retries at three for `429`. If the limit persists, reduce concurrency instead
   of extending the retry loop.
6. On `500 internal_error`, confirm whether the mutation had an effect before retrying. Poll
   `GET /v1/orders/{id}` or `GET /v1/wallet` first.

`Retry-After` is authoritative. Do not use a shorter fixed sleep.

## Capacity planning

- Quote, order and redeem limits are intentionally lower than read limits. A batch integration
  should queue writes rather than fan them out.
- A single large order consumes one order-creation token but up to 5,000 units. It does not
  multiply the request count.
- Daily quotas are per credential and call class. Multiple keys under the same partner still
  consume the account aggregate.
- Use webhooks and `GET /v1/orders/{id}` for status. Do not poll faster than the order-read
  limit.

## Contract status

The limit table above matches the running v1 service and the values returned by
`GET /v1/capabilities`. The older five-language guide still contains a per-second limit
table; treat this page and the capabilities response as current. The `quota_exceeded` envelope is
served today. The agent default line and unit caps are part of the target agent contract and are
not enforced by the current order handler.

If a limit response seems wrong, capture `X-Request-Id`, `RateLimit-Limit`,
`RateLimit-Remaining`, `RateLimit-Reset` and the UTC time, then contact partner support.
