# Rate limits

URL: https://docs.bithuman.ai/api/rate-limits

> Request limits per plan and tier, the 429 contract, and a retry strategy.

## Request limits

Requests are limited **per account** (every API secret on the account shares the same buckets), by endpoint cost tier and plan. Each cell is requests per minute; a bucket also allows a burst of that size and refills continuously.

| Cost tier | Free | Creator | Pro | Business | Enterprise* |
|---|---|---|---|---|---|
| **Generate** | 4 | 10 | 30 | 60 | 120 |
| **Write** | 30 | 60 | 180 | 360 | 720 |
| **Read** | 120 | 240 | 720 | 1440 | 2880 |

\* Enterprise defaults; custom limits are available from [sales](https://www.bithuman.ai/enterprise?topic=api-rate-limits#contact).

| Cost tier | Covers |
|---|---|
| **Generate** | heavy jobs: `POST /v1/agent/generate`, `POST /v1/dynamics/generate`, video generation; also `POST /v1/runtime-sessions/{session_id}/end` |
| **Write** | every other `POST`, `PUT`, `PATCH`, `DELETE`, such as `POST /v1/agent/{code}/speak`, plus `GET /v1/agent/{code}/sessions` |
| **Read** | other `GET` requests, such as `GET /v1/agent/status/*` and `GET /v2/credit-summaries` |

A plan change reaches the limiter within about a minute; no new secret is needed. Over the limit, the API returns `429 RATE_LIMITED` with a `Retry-After` header and the standard [error envelope](https://docs.bithuman.ai/api/errors).

**Never limited:** webhook deliveries, and the runtime-token routes (`/v1/runtime-tokens*`, `/v1/runtime/*`) that keep a live session authenticated. A live session is never cut off with a `429`.

**Failed authentication** is throttled per client IP at 30 failures per minute. Routes that check the secret themselves (embed-token and realtime mints, `/v1/me`, CLI sign-in) are limited per client IP, at 120 requests per minute, instead of per account.

## Session concurrency

| Plan | Concurrent cloud avatar sessions |
|---|---|
| Free | 1 |
| Creator | 3 |
| Pro | 10 |
| Business | 50 |
| Enterprise | 200 |
| Custom (contact sales) | Unlimited |

A session over the allowance is refused at start with [`403 CONCURRENCY_LIMIT_REACHED`](https://docs.bithuman.ai/api/errors#plan-and-credit-refusals), whose `upgrade_url` links the plans; a live session is never cut off by this limit. Every cloud avatar counts as its own session, including avatars that share a room name. Agent and dynamics generation jobs queue and run as capacity frees up.

A session stops counting the moment it ends: the room closes, the last user leaves, or you remove the avatar participant (`bithuman-avatar-agent`) from your LiveKit room. That holds for every cloud session: the Console, the web embed, and a cloud avatar in your own LiveKit room. To end one yourself and free its slot at once, [terminate the session](https://docs.bithuman.ai/api/runtime-sessions#terminate-a-session).

**Session length.** One continuous session can run up to 24 hours in the cloud and 7 days self-hosted. It then ends with `403 SESSION_DURATION_LIMIT`; start a new session to continue. For longer unattended installs (kiosks), [contact sales](https://www.bithuman.ai/enterprise?topic=api-rate-limits#contact).

Sessions you render on your own hardware are limited only by your credits ([self-hosting](https://docs.bithuman.ai/deploy/self-hosted)). Cost: active session time, to the second ([pricing](https://docs.bithuman.ai/pricing)).

## Response headers

Metered endpoints return your current state, so you can slow down before a `429`:

| Header | Meaning |
|---|---|
| `X-RateLimit-Limit` | your plan's limit for this request's cost tier |
| `X-RateLimit-Remaining` | whole requests left right now |
| `X-RateLimit-Reset` | Unix time when the bucket is full again |
| `Retry-After` | on `429` only: seconds to wait |
| `X-Request-Id` | include it when you contact support |

Not every response carries them (`POST /v1/validate` has none); fall back to backoff.

## Recommended retry strategy

Retry `429` and `5xx` with exponential backoff and jitter, honouring `Retry-After`:

```python
import time, random, requests

def call(method, url, max_retries=5, **kw):
    for attempt in range(max_retries):
        resp = requests.request(method, url, timeout=30, **kw)
        if resp.status_code not in (429, 502, 503, 504):
            return resp
        wait = float(resp.headers.get("Retry-After", 2 ** attempt))
        time.sleep(wait + random.uniform(0, 1))
    return resp
```

Usage: `call("POST", "https://api.bithuman.ai/v1/video/generate", headers=h, json={...})`.

## Best practices

- **Use [webhooks](https://docs.bithuman.ai/api/webhooks), not polling,** for `agent.ready` and `agent.failed`. If you poll status, poll every 5 seconds or slower.
- **Cache agent details** from `GET /v1/agent/{code}`; they rarely change.
- **Reuse a session** for back-to-back conversations rather than starting a new one; note that an open session bills its time, talking or idle.
- **Check your balance** with `GET /v2/credit-summaries` before creating an agent ([creation costs](https://docs.bithuman.ai/pricing#creation--one-time-credits)), to avoid a `402`.

More capacity comes with a higher [plan](https://docs.bithuman.ai/pricing#plans); for more than Enterprise, [contact sales](https://www.bithuman.ai/enterprise?topic=api-rate-limits#contact).
