> Agent-readable docs index: /llms.txt. Download /docs.zip to grep all markdown files locally.

---
title: Rate Limits
description: Request limits by plan and how to handle them.
---

# Rate Limits

Vakyam applies two independent, account-wide limits — both keyed on your
account, not per API key, so all keys on your account share them:

* A **rate limit** — how many requests you may start per minute.
* A **concurrency limit** — how many requests may be in flight at the same
  time.

They are orthogonal: staying under the rate limit does not exempt you from the
concurrency limit, and vice versa. Both values depend on your
[plan](/pricing).

## Limits by plan

| Plan      | Requests per minute | Concurrent requests |
| --------- | ------------------- | ------------------- |
| Free      | 15                  | 1                   |
| Developer | 60                  | 3                   |
| Growth    | 300                 | 10                  |

## Rate limit

The rate limit uses a sliding window. Your account's per-minute cap is set by
your plan (see the table above).

### What counts against the limit

Only speech-generation requests consume quota:

* `POST /v1/tts/generate`
* `POST /v1/tts/stream`
* Each WebSocket `text` message

Metadata requests such as `GET /v1/voices` do **not** count against your limit.

### Rate limit headers

Every response includes your current window state. The limit value matches your
plan:

```text
X-RateLimit-Limit:     60
X-RateLimit-Remaining: 58
X-RateLimit-Reset:     1715678460
```

* `X-RateLimit-Limit` — maximum requests per minute for your plan.
* `X-RateLimit-Remaining` — requests left in the current window.
* `X-RateLimit-Reset` — Unix timestamp when the window resets.

### When you exceed the rate limit

You receive `429 Too Many Requests` with a `Retry-After` header:

```json
{
  "error": {
    "status_code": 429,
    "code": "rate_limit_exceeded",
    "message": "You have exceeded 60 requests per minute. Retry after 23 seconds."
  }
}
```

Over WebSocket, the same condition is delivered as a JSON `error` message with
code `rate_limit_exceeded` and a `retry_after_seconds` field. The connection
stays open.

## Concurrency limit

Separately from the per-minute rate, your account may only have a limited number
of **synthesis requests in flight at the same time**. This keeps a single
account from monopolizing capacity while still under its per-minute rate.

Your concurrency cap is set by your plan (see the table above). The limit is
keyed on your account, so all of an account's API keys share one concurrency
budget.

What counts as one in-flight unit:

* **HTTP** — each `POST /v1/tts/generate` and `POST /v1/tts/stream` request
  counts while it is running, and frees its slot when it finishes (on success or
  error).
* **WebSocket** — each open session counts as **one** in-flight unit for the
  entire lifetime of the connection, from the first `config` until the socket
  closes — not per `text` message. An idle-but-open session still holds its slot
  because it keeps synthesis capacity reserved.

### When you exceed the concurrency limit

You receive `429 Too Many Requests` with the code `concurrency_limit_exceeded`:

```json
{
  "error": {
    "status_code": 429,
    "code": "concurrency_limit_exceeded",
    "message": "This account already has 3 synthesis requests in flight, which is the maximum allowed at once. Wait for one to finish before starting another."
  }
}
```

> **Note:**
> Unlike `rate_limit_exceeded`, this response has **no `Retry-After` header**. A
> concurrency slot has no fixed reset time — it frees only when one of your
> account's other in-flight requests finishes. Retry once an outstanding request
> completes.

Over WebSocket the same condition is delivered as a JSON `error` message with
code `concurrency_limit_exceeded`.

## Handling limits gracefully

> **Warning:**
> Do not retry immediately on a `429`. Wait until the time indicated by
> `Retry-After` (or `X-RateLimit-Reset`), then retry with exponential backoff and
> jitter.

#### Python

```python
import time
from vakyamai import RateLimitError

try:
    client.tts.generate(
        text="...", model_id="raaga-v1", voice="Archana", language="ta-IN",
    )
except RateLimitError as exc:
    time.sleep(exc.retry_after_seconds or 5)
```

If you consistently hit rate or concurrency limits, [upgrade your
plan](/pricing) for higher caps.

---

*Powered by [holocron.so](https://holocron.so)*
