Rate limits and timeouts
For account-backed keys, limits apply to the KittenML organization rather than to each key separately. Two keys owned by the same organization share the same capacity. Older migrated ASR keys that are not attached to an organization are limited independently per key.
Current limits
| Workload | Concurrent requests or sessions |
|---|---|
| Upload and realtime ASR combined | 5 |
| Streaming TTS | 2 |
There is currently no requests-per-minute or hourly audio quota in addition to these concurrency limits.
When a slot is active
ASR
Upload and realtime STT share one pool of five slots.
- An upload holds a slot after admission until transcription succeeds or fails.
- A realtime WebSocket or WebRTC call holds a slot from session admission until the session closes.
- A long-running realtime session therefore reduces the number of simultaneous uploads available to the same organization.
TTS
A TTS request holds one of two slots while speech is generated and streamed. The slot is released when the stream completes, fails, or disconnects.
Separately from your organization's limit, a Kitten TTS 2 request that arrives
while hosted generation capacity is momentarily full can wait up to about 8
seconds for a free generation slot before its audio starts. If no slot frees
up in that time, it returns 503 with Retry-After; retry with backoff.
Voice cloning
Voice cloning requests—one-request references, saved voices, and
consents—can run at the same time. When many arrive together, a request waits
in a short queue for a free cloning slot. If the queue is full, or the request
has waited about two minutes, it returns 429 with
"code": "custom_voice_creation_busy"; wait a moment and retry with backoff.
A one-request reference is also a TTS request and holds one of the
organization's TTS slots. See Clone a voice.
HTTP limit response
An upload or TTS request above the active limit returns
429 Too Many Requests:
{
"error": {
"message": "Organization has too many concurrent ASR jobs or sessions.",
"type": "rate_limit_error",
"param": null,
"code": "rate_limit_exceeded"
},
"request_id": "<request-id>"
}
Rejected upload STT responses include:
x-ratelimit-limit-concurrent-sessions: 5
x-ratelimit-remaining-concurrent-sessions: 0
Retry-After: 1
A rejected TTS request includes:
x-ratelimit-limit-concurrent-requests: 2
x-ratelimit-remaining-concurrent-requests: 0
Retry-After: 1
Header names are case-insensitive.
WebSocket limit event
A realtime WebSocket completes its upgrade before admission errors are sent.
When capacity is full, it emits an error event with
code: "rate_limit_exceeded" and then closes. Close codes differ by
route—realtime STT uses 1000, incremental-input TTS uses 1008—so use
error.code, not the close code, to classify the failure. Because this is a
WebSocket event rather than an HTTP 429 response, the client does not
receive a Retry-After header. Wait before opening a new session and use
backoff with jitter if capacity remains full.
WebRTC performs admission during the SDP signaling request. If capacity is
full, POST /v1/realtime/calls returns an HTTP 429 response before media is
established.
Client behavior
- For HTTP
429, wait at leastRetry-Afterseconds. - Retry with exponential backoff and random jitter.
- Limit retries and surface persistent overload to the caller.
- Reuse active realtime sessions when your application naturally has multiple turns in one conversation.
Timeouts and size limits
Text-to-speech
| Use case | Public hard limit | Recommended usage | Other safeguards |
|---|---|---|---|
| Complete-response SDK usage | 40,000 characters/request | 400–5,000 characters | 256 KiB JSON body; 30-minute request timeout |
| HTTP binary output streaming | 40,000 characters/request | 400–5,000 characters | Same endpoint and limits as complete-response usage |
| HTTP SSE output streaming | 40,000 characters/request | 400–5,000 characters | Require terminal speech.audio.done |
| WebSocket input and output streaming | 262,144 cumulative characters/session | Send 50–500 characters at a time, preferably complete phrases | 8,192 characters/message; 64 KiB frame; five-minute idle timeout; two-hour session limit |
All API limits
| Limit | Value |
|---|---|
| Upload audio file | 25 MiB |
| Realtime decoded audio append | 15 MiB |
| Realtime WebSocket message | 24 MiB |
| TTS HTTP JSON request body | 256 KiB |
| TTS HTTP input text | 40,000 characters |
| TTS HTTP request duration | 30 minutes |
| TTS input-streaming session text | 262,144 cumulative characters |
| TTS input-streaming append | 8,192 characters |
| TTS input-streaming WebSocket frame | 64 KiB |
| TTS input-streaming idle timeout | 5 minutes |
| TTS input-streaming session duration | 2 hours |
Realtime WebSocket and WebRTC sessions have no fixed duration limit. Clients should close unused sessions explicitly so their organization capacity is released promptly.