Skip to content

Limits & quotas

These are the limits and quotas the API enforces at v0. They are the single source of truth — the SDKs surface them as constants and the docs link here.

| Limit | Default | Where enforced | | -------------------------------- | -------------- | ------------------------------------- | | max_duration_seconds | 600 (10 min) | Per-session field; worker terminates. | | max_duration_seconds ceiling | 3600 (1 hr) | API rejects creates above this. | | idle_timeout_seconds | 30 | Per-session field; worker terminates. | | startup_timeout_seconds | 15 | Worker → job failure if exceeded. | | metadata JSON size | 8 KB | API request validation. |

If a session runs past max_duration_seconds, the worker terminates it cleanly (session.ended, reason max_duration). If no audio arrives for idle_timeout_seconds, it ends with reason idle_timeout. If the scheduler can’t place the job within startup_timeout_seconds, the session goes to failed with code no_capacity.

| Limit | Default | Where enforced | | -------------------------------------- | ----------------------- | ---------------------------------------- | | Concurrent sessions per API key | 1 (v0) | Control plane refuses create on excess. | | Concurrent sessions per org | 5 (v0; tunable per-org) | Same. | | Concurrent sessions per org (ceiling) | 20 (v0) | Same. |

Exceeding a concurrency cap returns 429 quota_exceeded with code concurrent_sessions. Per-org limits can be raised by support; there is no self-service override at v0.

| Limit | Default | Response | | --------------------------- | -------------------- | ------------------------- | | POST /v1/sessions | 10 req / min / key | 429 rate_limit |

Rate-limited responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers; a 429 adds Retry-After. See Errors.

| Limit | Default | Notes | | ------------------ | ------- | ------------------------------ | | Idempotency window | 24 h | Per Idempotency-Key + body. |

Within the window, the same key + same body returns the original response; the same key + a different body returns 409 conflict. See Sessions → idempotent creates.

| Item | Default | Notes | | --------------------------- | ------------------ | ---------------------------------------- | | Free credit grant at signup | $20 USD equivalent | Applied automatically; non-renewable. |

metadata is a free-form, customer-owned JSON object — except keys prefixed with _avatar., which are reserved for platform flags. v0 reserved keys:

| Key | Type | Effect | | ---------------------- | ---- | ----------------------------------------------------------- | | _avatar.debug_record | bool | Opt in to 24h retention of raw audio for debugging. |

Supplying any other _avatar.* key returns 400 invalid_request with code metadata.reserved_key.