# Rate limits and pools

What an account can call, and how fast, depends on its pool. Pools group models and carry an included daily allowance and a per-minute limit. `GET /v1/models` shows what applies to the calling account.

## Pools

| Pool | Opens | Models | Included per UTC day | Per minute |
|---|---|---|---|---|
| Public | At registration | `ppocr-v6`, `dinov3`, `siglip2` | 100 calls | 10 |
| Free | After the first top-up | The public models and `sam-lite` | 1,000 calls | 60 (included calls only) |
| Paid | After the first top-up | Every model: `sam3`, `paddleocr-vl` and `birefnet` are available only here | Not applicable: billed per call | No fixed limit |

- A registered account uses the public pool. Calls beyond the daily allowance are refused with `429 daily_limit_reached`.
- A funded account (one that has been topped up) also gets the free pool. The first 1,000 calls per UTC day of each pool model are free; calls beyond that are billed from the balance.
- `sam3`, `paddleocr-vl` and `birefnet` are always billed from the balance. A call to a model that the account may not use yet answers `403 model_locked`, and `GET /v1/models` reports what unlocks it in `unlockedBy`.
- The daily allowance resets at 00:00 UTC. The calls of an account are counted together, whichever key made them. A failed call gives its slot back.

The `billing` object of each response shows which pool covered the call and today's count. See [Billing](https://stack.foldbun.com/docs/billing/).

## Per-minute limit

The per-minute limit is a token bucket per account: the burst equals the per-minute limit and tokens refill continuously. Exceeding it answers `429 rate_limited` with a `Retry-After` header. The limit is shared by every key of the account and is the one of the pool that serves the model.

On a funded account the free pool's 60 per minute paces the included daily calls only. A call beyond the daily allowance, or one that arrives while the 60 per minute are in use, is billed from the balance at the normal price and is not rate limited; the allowance stays available for later calls and is not used by that call. Only a call that cannot be paid from the balance answers `429 rate_limited` in that case. Concurrent calls remain capped by the account's concurrency limit. Batch requests follow the same rule: a batch takes one token, and when none is left its items are billed instead of free. Registered accounts (public pool only) keep the 429.

When the account has no fixed limit, a shortage of GPU capacity is reported as `503 model_busy` or `503 model_unavailable` instead.

## Reading the limits

`GET /v1/models` is free, not metered and not rate limited by pool. Each model carries the fields that describe the calling account.

| Field | Meaning |
|---|---|
| `available` | Whether the account may call the model now. |
| `pool` | The pool serving the account: `public`, `free` or `paid`. `null` when the model is not available. |
| `freeDailyCalls` | Included calls per UTC day at no charge. `null` when there is none. |
| `perMinute` | Calls per minute. `null` when there is no limit. |
| `unlockedBy` | What unlocks the model when it is not available, for example `top-up`. |

```json
{
  "id": "ppocr-v6",
  "name": "PP-OCRv6 small",
  "task": "ocr",
  "endpoints": ["/v1/ocr"],
  "license": "Apache-2.0",
  "prices": [{ "unit": "image", "price": 0.25 }],
  "available": true,
  "pool": "public",
  "freeDailyCalls": 100,
  "perMinute": 10,
  "unlockedBy": null
}
```

## Status codes

| Status | Code | Cause | Action |
|---|---|---|---|
| 402 | `insufficient_balance` | The balance cannot cover the call. | Add credit. |
| 403 | `model_locked` | The pool or the key scope does not include the model. | Add credit, or use a key with the model in scope. |
| 429 | `rate_limited` | The per-minute limit was reached (funded accounts: and the balance cannot pay for the call). | Wait for `Retry-After`, then repeat. |
| 429 | `daily_limit_reached` | The daily allowance of the public pool was used. | Add credit, or wait until the next UTC day. |

See [Errors](https://stack.foldbun.com/docs/errors/) for the full list.
