Rooms
Last updated September 4, 2026
Multi-party audio conference rooms, including audio bridges between room mixers
List all rooms with participants
Responses
200
Array of rooms
Create a room
Request Body
| Field | Type | | Description |
|---|
id | string | required | Custom room ID (auto-generated UUID if omitted) |
webhook_url | string(uri) | optional | Route all events for this room exclusively to this URL instead of global webhooks. |
webhook_secret | string | optional | HMAC-SHA256 signing secret for the per-room webhook. |
app_id | string | optional | Application identifier. Carried through to all events for this room. Use to filter the WebSocket event stream by app. |
sample_rate | enum | optional | Mixer sample rate in Hz. Allowed values: 8000, 16000, 48000. Default: 16000. 16000Values: 8000, 16000, 48000 |
Responses
201
Room created| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
id | string | required | Room identifier |
app_id | string | optional | Application identifier for event stream filtering. |
sample_rate | integer | required | Mixer sample rate in Hz (8000, 16000, or 48000). |
participants | array[object] | required | Legs currently in this room |
409
Room ID already exists| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Get a room with participants
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
200
Room details| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
id | string | required | Room identifier |
app_id | string | optional | Application identifier for event stream filtering. |
sample_rate | integer | required | Mixer sample rate in Hz (8000, 16000, or 48000). |
participants | array[object] | required | Legs currently in this room |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Delete a room
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
200
Room deleted| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Add or move a leg to a room
Add a leg to a room (auto-creates room if it doesn't exist). If the leg is already in a different room, it is atomically moved to the target room. A ringing inbound SIP leg is automatically answered before being added — in this case the response status is adding and the actual room join happens asynchronously, observable via leg.joined_room. Auto-answer failures surface as leg.command_failed with command="add_to_room". Only the leg's primary audio stream joins by default; streams additionally mixes named secondary streams of the same leg into this room. A stream currently mixed elsewhere is moved here.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
leg_id | string | required | ID of the leg to add |
mute | boolean | optional | If set, apply this mute state to the leg atomically before it joins the mixer (no race where un-muted audio enters the mix). Omit to leave current state untouched (useful when moving between rooms). |
deaf | boolean | optional | If set, apply this deaf state to the leg atomically before it joins the mixer. Omit to leave current state untouched. |
accept_dtmf | boolean | optional | If set, control whether this leg receives DTMF digits broadcast from other legs in the same room. Omit to leave current state untouched (default for new legs is true). |
role | string | optional | If set, apply this routing role to the leg atomically before it joins the mixer. The room's routing matrix (see PUT /v1/rooms/{id}/routing) decides which other legs this leg hears and is heard by based on roles. Pass "" to clear the role (full mesh). Omit to leave the current role untouched. |
streams | array[object] | optional | Additional audio streams of the leg to mix into this room, each with its own routing role. Omit to add only the leg's primary stream. A stream already mixed elsewhere is moved here. |
Responses
200
Leg added or moved| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid JSON, leg not found, or leg not connected| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Remove a leg from a room
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
legID | path | string | required | Leg ID |
Responses
200
Leg removed| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Room or leg not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
List bridges involving this room
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
200
Array of bridges (direction relative to the path room)
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Bridge this room's mixer to another room's mixer
Joins the room in the path with room_id so audio flows between their mixers. Both rooms must exist and share a sample rate. direction is relative to the room in the path: bidirectional, send (path room → other), receive (other → path room), or none (allocated but silent). Bridging rooms into a cycle with feedback-enabled directions causes audio feedback — use one-way directions to break loops.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
id | string | optional | Custom bridge ID (auto-generated UUID if omitted) |
room_id | string | required | The other room to join. Must use the same sample rate as the room in the path. |
direction | enum | optional | Audio flow relative to the room in the path: bidirectional (both hear each other), send (path room → other only), receive (other → path room only), none (allocated but silent). Default: bidirectional. "bidirectional"Values: bidirectional, send, receive, none |
Responses
201
Bridge created| Field | Type | | Description |
|---|
id | string | required | Bridge identifier |
room_id | string | required | The peer room joined to the room in the path |
direction | enum | required | Audio flow relative to the room in the path: bidirectional, send, receive, or none. Values: bidirectional, send, receive, none |
sample_rate | integer | required | Shared mixer sample rate in Hz (both rooms must match). |
400
Invalid JSON, self-bridge, sample-rate mismatch, or invalid direction| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Path room or room_id not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
A bridge between these rooms already exists| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Get a bridge involving this room
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
bridgeID | path | string | required | |
Responses
200
Bridge details (direction relative to the path room)| Field | Type | | Description |
|---|
id | string | required | Bridge identifier |
room_id | string | required | The peer room joined to the room in the path |
direction | enum | required | Audio flow relative to the room in the path: bidirectional, send, receive, or none. Values: bidirectional, send, receive, none |
sample_rate | integer | required | Shared mixer sample rate in Hz (both rooms must match). |
404
Bridge not found for this room| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Change a bridge's audio flow direction
Live-updates the direction (relative to the room in the path) without interrupting audio.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
bridgeID | path | string | required | |
Request Body
| Field | Type | | Description |
|---|
direction | enum | required | New audio flow relative to the room in the path: bidirectional, send, receive, or none. Values: bidirectional, send, receive, none |
Responses
200
Bridge updated| Field | Type | | Description |
|---|
id | string | required | Bridge identifier |
room_id | string | required | The peer room joined to the room in the path |
direction | enum | required | Audio flow relative to the room in the path: bidirectional, send, receive, or none. Values: bidirectional, send, receive, none |
sample_rate | integer | required | Shared mixer sample rate in Hz (both rooms must match). |
400
Invalid JSON or invalid/missing direction| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Bridge not found for this room| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Tear down a bridge
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
bridgeID | path | string | required | |
Responses
200
Bridge deleted| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
404
Bridge not found for this room| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Get the room's audio routing matrix
Returns the per-listener-role source whitelist used by the room's audio mixer. A listener role absent from the matrix defaults to full mesh (hears every other leg). A role with an empty [] list is an isolated listener that hears nothing.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
200
Current matrix| Field | Type | | Description |
|---|
matrix | object | required | Listener-role → list of allowed source roles. Roles absent from the matrix default to full mesh. |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Replace the room's audio routing matrix
Atomically replaces the room's audio routing matrix and recomputes every leg's per-listener source whitelist in one mixer-mutex acquisition. The next mix tick (≤ 20 ms) reflects the new routing. Roles are operator-supplied strings (e.g. "customer", "agent", "supervisor"). A leg with no role defaults to full mesh.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
matrix | object | required | Listener-role → list of allowed source roles. Omitted listener roles default to full mesh. Empty list = hears nothing. |
Responses
200
Updated matrix| Field | Type | | Description |
|---|
matrix | object | required | Listener-role → list of allowed source roles. Roles absent from the matrix default to full mesh. |
400
Invalid JSON| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Replace selected rows of the room's audio routing matrix
Replaces the listed listener-role rows. Pass "sources": null on an update to clear that row back to full mesh.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
updates | array[object] | required | Per-listener-role row replacements applied as a single atomic update. |
Responses
200
Updated matrix| Field | Type | | Description |
|---|
matrix | object | required | Listener-role → list of allowed source roles. Roles absent from the matrix default to full mesh. |
400
Invalid JSON| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Fork a room to an external SIPREC recording server
Originates a SIPREC recording session (RFC 7866) to the given recording server, offering one sendonly m=audio section per room participant and carrying an RFC 7865 metadata document that names each party and binds it to a section's a=label. Each participant's own audio is forked to its own section — not the room mix. Returns the resulting siprec_out leg; delete that leg to end the session. Requires SIPREC_SRC_ENABLED=true.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
srs_uri | string | required | SIP URI of the session recording server, e.g. "sip:srs@recorder.example.com:5060;transport=tcp". A recording session carries the metadata document alongside the SDP and exceeds the UDP message limit, so the target should accept TCP. The transport comes from the URI: ";transport=tcp", or "sips:" / ";transport=tls" for TLS. |
leg_ids | array[string] | optional | Which participants to record. Each entry is either a leg ID (that leg's own audio) or "<legID>#<streamID>" for one of a leg's secondary audio streams mixed into the room. Empty or absent records every participant. An entry that is not in the room is a 404. |
session_id | string | optional | Communication session identifier put in the recording metadata. Defaults to the room ID. |
app_id | string | optional | Application identifier tagged onto the resulting leg and its events. |
auth_username | string | optional | SIP digest username, when the recording server challenges the INVITE. |
auth_password | string | optional | SIP digest password, when the recording server challenges the INVITE. |
headers | object | optional | Extra SIP headers to include in the INVITE. Require: siprec is always sent. |
Responses
201
Recording session established| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
id | string | required | Unique leg identifier (UUID) |
type | enum | required | Leg type Values: sip_inbound, sip_outbound, webrtc, whatsapp_in, whatsapp_out, websocket_in, websocket_out, moq_in, livekit_publish, livekit_participant |
state | enum | required | Leg state Values: ringing, early_media, connected, held, hung_up |
room_id | string | optional | Room ID if the leg is in a room, empty otherwise |
muted | boolean | required | Whether the leg is muted (cannot be heard by others) |
deaf | boolean | required | Whether the leg is deaf (cannot hear others) |
accept_dtmf | boolean | required | Whether the leg receives DTMF digits broadcast from other legs in the same room. Defaults to true. |
held | boolean | required | Whether the call is on hold (SIP legs only) |
role | string | optional | Routing role used by the room's audio routing matrix (e.g. "customer", "agent", "supervisor"). Empty string means unroled (full mesh). |
app_id | string | optional | Application identifier for event stream filtering. |
sip_headers | object | optional | Deprecated: X-* headers from the inbound INVITE. Only present on sip_inbound legs. Use `headers` for new code; it carries the same map plus surfaces handshake headers for websocket legs. |
headers | object | optional | Custom protocol headers exposed by the leg's transport — X-/P- headers from a SIP INVITE, the WebSocket upgrade request, or supplied at outbound dial time. |
custom_data | any | optional | Opaque application JSON attached to the leg. Any JSON value is accepted (object, array, string, number, boolean). It is echoed on the leg view and carried at the top level of every event published for this leg, so external state can be correlated without keeping a leg_id lookup table. Capped by CUSTOM_DATA_MAX_BYTES (default 1024 bytes, 0 = unlimited). |
400
Invalid JSON or srs_uri| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
403
Outbound SIPREC is disabled| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
Room has no participants, or more than SIPREC_MAX_STREAMS| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
502
The recording server rejected the session| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Play audio to a room
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
url | string(uri) | required | URL of the audio file (mutually exclusive with tone) |
tone | string | required | Built-in telephone tone name. Format: {country}_{type} or bare {type} (defaults to US). Types: ringback, busy, dial, congestion. Countries: us, gb, de, fr, au, jp, it, in, br, pl, ru. Examples: us_ringback, gb_busy, dial. |
mime_type | string | required | MIME type (e.g. audio/wav). Required when using url. |
repeat | integer | required | Number of times to repeat playback (url only) 0 |
volume | integer | required | Volume adjustment in dB (-8 to 8) 0 |
Responses
200
Playback started| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid JSON or volume out of range| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
Room has no participants| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Change the volume of an active room playback
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
playbackID | path | string | required | Playback ID |
Request Body
| Field | Type | | Description |
|---|
volume | integer | required | Volume adjustment (-8 to 8, ~3dB per step, 0 = unchanged) |
Responses
200
Volume updated| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid JSON or volume out of range| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Playback not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Stop room playback
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
playbackID | path | string | required | Playback ID |
Responses
200
Playback stopped| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
404
No playback in progress| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Synthesize speech and play it into a room
Synthesizes the provided text using the configured TTS provider and plays the audio into the room. When TTS_CACHE_ENABLED=true, identical requests (same text, voice, model, language, and prompt) are stored on disk in TTS_CACHE_DIR and persist across restarts, without calling the external provider.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
text | string | required | Text to synthesize |
voice | string | required | Provider-specific voice identifier. ElevenLabs: voice name or ID. AWS Polly: voice ID (e.g. Joanna, Matthew). Google Cloud: voice name — either full format (e.g. en-US-Neural2-F) or short name for Gemini models (e.g. Achernar, Kore). Deepgram: model name (e.g. aura-2-asteria-en). |
model_id | string | required | Provider-specific model/engine. ElevenLabs: model ID. AWS Polly: engine (standard, neural, long-form, generative; default neural). Google Cloud: model name (e.g. gemini-2.5-pro-tts, chirp3-hd). |
language | string | optional | Language code (e.g. "en-US", "pl-pl"). Required for Google Gemini TTS voices that use short names (e.g. Achernar). Auto-extracted from full voice names like en-US-Neural2-F. |
prompt | string | optional | Style/tone instruction for promptable voice models (Google Gemini TTS only). E.g. "Read aloud in a warm, welcoming tone." |
volume | integer | required | Volume adjustment in dB (-8 to 8) 0 |
provider | enum | optional | TTS provider: "elevenlabs" (default), "aws", "google", or "deepgram" Values: elevenlabs, aws, google, deepgram |
api_key | string | optional | ElevenLabs: API key override (falls back to ELEVENLABS_API_KEY env var). AWS: optional ACCESS_KEY:SECRET_KEY override (falls back to default AWS credential chain). Google Cloud: optional API key override (falls back to Application Default Credentials). Deepgram: API key override (falls back to DEEPGRAM_API_KEY env var). |
Responses
200
TTS playback started| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid JSON, missing text/voice, or volume out of range| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
Room has no participants| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
503
No API key provided for the selected provider| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Start recording the room mix to a WAV file
Records the full room mix at 16kHz, 16-bit, mono.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
storage | enum | required | "file" (default) — local disk, "s3" — upload to S3 after recording stops, "gcs" — upload to Google Cloud Storage via the native GCS API (Application Default Credentials / Workload Identity) Values: file, s3, gcs |
multi_channel | boolean | required | When true, record each participant to a separate mono WAV file in addition to the full mix. Only applies to room recordings. false |
s3_bucket | string | required | S3 bucket name. Overrides S3_BUCKET env var. Required if env var is not set. |
s3_region | string | required | AWS region. Overrides S3_REGION env var. Default us-east-1. |
s3_endpoint | string | required | Custom S3 endpoint (MinIO, etc.). Overrides S3_ENDPOINT env var. |
s3_prefix | string | required | Key prefix (e.g. recordings/). Overrides S3_PREFIX env var. |
s3_access_key | string | required | AWS access key ID. Overrides default credential chain. |
s3_secret_key | string | required | AWS secret access key. Must be set together with s3_access_key. |
gcs_bucket | string | required | GCS bucket name. Overrides GCS_BUCKET env var. Required if env var is not set when storage=gcs. |
gcs_object_name_prefix | string | required | Object name prefix (e.g. recordings or recordings/). Overrides GCS_OBJECT_NAME_PREFIX env var. A trailing slash is added automatically when missing. |
filename | string | required | Optional output basename for the WAV file. A .wav suffix is added when missing. Must be a single path segment (no directories). Dots inside the name are preserved (only a trailing .wav is treated as the extension). Rejected with 409 if the file already exists or another recording is using the same name. When omitted, a timestamped name is generated. |
Responses
200
Recording started| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid storage type, S3 not configured, or invalid S3 credentials| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
Room has no audio sources (no leg participants and no attached streams)| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
500
Failed to create recording file| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Stop room recording
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
200
Recording stopped| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
404
No recording in progress| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Pause a room recording
Replaces the room mix with silence on the active recording until /record/resume is called. When multi-channel recording is active, every per-participant track is paused too (including tracks for participants who join while paused). Idempotent: returns status: already_paused when already paused.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
200
Recording paused (or already paused)| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
404
No recording in progress| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Resume a paused room recording
Resumes writing real audio after a prior /record/pause. Resumes every per-participant track if multi-channel recording is active. Idempotent.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
200
Recording resumed (or was not paused)| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
404
No recording in progress| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Start speech-to-text on all room participants
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
language | string | required | Language code (e.g. "en", "es") |
partial | boolean | required | Emit partial (non-final) transcripts false |
provider | enum | optional | STT provider: "elevenlabs" (default), "deepgram" (/v1/listen), "deepgram_flux" (/v2/listen, conversational turn detection), "azure" or "speechmatics" Values: elevenlabs, deepgram, deepgram_flux, azure, speechmatics |
api_key | string | optional | API key override (falls back to ELEVENLABS_API_KEY, DEEPGRAM_API_KEY, AZURE_SPEECH_KEY or SPEECHMATICS_API_KEY env var depending on provider) |
model | string | optional | Provider-specific model. Deepgram: default "nova-3". Deepgram Flux: "flux-general-en" (default) or "flux-general-multi". Speechmatics: "standard" (default) or "enhanced". |
keyterms | array[string] | optional | Terms to boost recognition of (Deepgram, Deepgram Flux, and Speechmatics — where they become additional_vocab). |
endpointing | integer | optional | Deepgram: milliseconds of silence before a segment is finalized; 0 disables endpointing. Speechmatics: maps to max_delay, clamped to 700-4000 ms; 0 leaves the provider default. |
utterance_end_ms | integer | optional | Deepgram: milliseconds of silence after which an stt.turn event with event=utterance_end is emitted. Deepgram requires interim results for this, which are requested automatically and still suppressed unless partial is true. Speechmatics: milliseconds of silence that close a turn and emit an stt.turn event with event=end_of_turn — default 600, capped at 2000, and 0 disables turn detection. |
eager_eot_threshold | number | optional | Deepgram Flux only: end-of-turn confidence that fires an eager_end_of_turn stt.turn event, enabling speculative generation. Must be between 0.3 and 0.9. When unset, no eager_end_of_turn or turn_resumed events are emitted at all. |
eot_threshold | number | optional | Deepgram Flux only: end-of-turn confidence required to close a turn. Deepgram default 0.7. |
eot_timeout_ms | integer | optional | Deepgram Flux only: milliseconds of silence after which a turn is closed regardless of confidence. Deepgram default 5000. |
language_hints | array[string] | optional | Deepgram Flux only: candidate language codes for the "flux-general-multi" model. |
Responses
200
STT started| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
STT already running, or the room has no audio sources (no leg participants and no attached streams)| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
503
No ElevenLabs API key provided| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Stop speech-to-text on a room
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
200
STT stopped| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
404
No STT in progress| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Attach an ElevenLabs ConvAI agent to a room
The agent joins as a virtual participant, hearing all participants (mixed-minus-self) and speaking to everyone.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
agent_id | string | required | ElevenLabs agent ID |
first_message | string | optional | Override the agent's first message |
language | string | optional | Language code (e.g. "en", "es") |
dynamic_variables | object | optional | Key-value pairs passed to the agent as dynamic variables |
api_key | string | optional | API key override (falls back to ELEVENLABS_API_KEY env var) |
Responses
200
Agent started| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid JSON or missing agent_id| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
Agent already attached to this room| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
503
No ElevenLabs API key provided| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Attach a VAPI agent to a room
The agent joins as a virtual participant, hearing all participants (mixed-minus-self) and speaking to everyone.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
assistant_id | string | required | VAPI assistant ID |
first_message | string | optional | Override the agent's first message |
variable_values | object | optional | Key-value pairs passed as VAPI variable values (assistantOverrides.variableValues) |
api_key | string | optional | API key override (falls back to VAPI_API_KEY env var) |
Responses
200
Agent started| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid JSON or missing assistant_id| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
Agent already attached to this room| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
503
No VAPI API key provided| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Attach a Pipecat bot to a room
The bot joins as a virtual participant via WebSocket, hearing all participants (mixed-minus-self) and speaking to everyone.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
websocket_url | string(uri) | required | WebSocket URL of the Pipecat bot (e.g. ws://my-bot:8765) |
Responses
200
Agent started| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid JSON or missing websocket_url| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
Agent already attached to this room| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Attach a Deepgram Voice Agent to a room
The agent joins as a virtual participant, hearing all participants (mixed-minus-self) and speaking to everyone.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
settings | object | optional | Full Deepgram agent settings object (agent.listen, agent.think, agent.speak, etc.). When omitted, sensible defaults are used (nova-3 STT, gpt-4o-mini LLM, aura-2-asteria-en TTS). |
greeting | string | optional | Agent greeting message |
language | string | optional | Language code (e.g. "en", "es") |
api_key | string | optional | API key override (falls back to DEEPGRAM_API_KEY env var) |
Responses
200
Agent started| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid JSON| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
Agent already attached to this room| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
503
No Deepgram API key provided| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Inject a message into a running agent session on a room
Sends a context message or instruction to the running agent. Supported by Deepgram (InjectAgentMessage), Pipecat (TextFrame), and VAPI (control URL). Returns 501 for ElevenLabs.
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Request Body
| Field | Type | | Description |
|---|
message | string | required | Context or instruction to inject into the running agent session |
Responses
200
Message sent| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
400
Invalid JSON or missing message| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
404
No agent attached to this room| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
409
Agent session not running| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
501
Provider does not support message injection| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Detach the agent from a room
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
200
Agent stopped| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
404
No agent attached to this room| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
WebSocket audio stream for a room
Upgrades to a WebSocket connection and joins the room as a bidirectional audio participant. The client sends and receives 16kHz 16-bit signed little-endian PCM audio (mono), base64-encoded in JSON text frames. Each audio frame is 640 bytes (20ms).
Parameters
| Name | In | Type | | Description |
|---|
id | path | string | required | Room ID |
Responses
101
WebSocket upgrade successful. Server sends a `connected` message followed by mixed-minus-self audio frames.
404
Room not found| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Schemas
Objects used by the Rooms endpoints above.
| Field | Type | | Description |
|---|
leg_id | string | required | ID of the leg to add |
mute | boolean | optional | If set, apply this mute state to the leg atomically before it joins the mixer (no race where un-muted audio enters the mix). Omit to leave current state untouched (useful when moving between rooms). |
deaf | boolean | optional | If set, apply this deaf state to the leg atomically before it joins the mixer. Omit to leave current state untouched. |
accept_dtmf | boolean | optional | If set, control whether this leg receives DTMF digits broadcast from other legs in the same room. Omit to leave current state untouched (default for new legs is true). |
role | string | optional | If set, apply this routing role to the leg atomically before it joins the mixer. The room's routing matrix (see PUT /v1/rooms/{id}/routing) decides which other legs this leg hears and is heard by based on roles. Pass "" to clear the role (full mesh). Omit to leave the current role untouched. |
streams | array[object] | optional | Additional audio streams of the leg to mix into this room, each with its own routing role. Omit to add only the leg's primary stream. A stream already mixed elsewhere is moved here. |
| Field | Type | | Description |
|---|
stream_id | string | required | Stream identifier from GET /v1/legs/{id}/streams. The primary stream is not addressable here — it joins with the leg itself. |
role | string | optional | Routing role for this stream inside the room. |
| Field | Type | | Description |
|---|
message | string | required | Context or instruction to inject into the running agent session |
| Field | Type | | Description |
|---|
id | string | required | Bridge identifier |
room_id | string | required | The peer room joined to the room in the path |
direction | enum | required | Audio flow relative to the room in the path: bidirectional, send, receive, or none. Values: bidirectional, send, receive, none |
sample_rate | integer | required | Shared mixer sample rate in Hz (both rooms must match). |
| Field | Type | | Description |
|---|
id | string | optional | Custom bridge ID (auto-generated UUID if omitted) |
room_id | string | required | The other room to join. Must use the same sample rate as the room in the path. |
direction | enum | optional | Audio flow relative to the room in the path: bidirectional (both hear each other), send (path room → other only), receive (other → path room only), none (allocated but silent). Default: bidirectional. "bidirectional"Values: bidirectional, send, receive, none |
| Field | Type | | Description |
|---|
settings | object | optional | Full Deepgram agent settings object (agent.listen, agent.think, agent.speak, etc.). When omitted, sensible defaults are used (nova-3 STT, gpt-4o-mini LLM, aura-2-asteria-en TTS). |
greeting | string | optional | Agent greeting message |
language | string | optional | Language code (e.g. "en", "es") |
api_key | string | optional | API key override (falls back to DEEPGRAM_API_KEY env var) |
| Field | Type | | Description |
|---|
agent_id | string | required | ElevenLabs agent ID |
first_message | string | optional | Override the agent's first message |
language | string | optional | Language code (e.g. "en", "es") |
dynamic_variables | object | optional | Key-value pairs passed to the agent as dynamic variables |
api_key | string | optional | API key override (falls back to ELEVENLABS_API_KEY env var) |
| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
id | string | required | Unique leg identifier (UUID) |
type | enum | required | Leg type Values: sip_inbound, sip_outbound, webrtc, whatsapp_in, whatsapp_out, websocket_in, websocket_out, moq_in, livekit_publish, livekit_participant |
state | enum | required | Leg state Values: ringing, early_media, connected, held, hung_up |
room_id | string | optional | Room ID if the leg is in a room, empty otherwise |
muted | boolean | required | Whether the leg is muted (cannot be heard by others) |
deaf | boolean | required | Whether the leg is deaf (cannot hear others) |
accept_dtmf | boolean | required | Whether the leg receives DTMF digits broadcast from other legs in the same room. Defaults to true. |
held | boolean | required | Whether the call is on hold (SIP legs only) |
role | string | optional | Routing role used by the room's audio routing matrix (e.g. "customer", "agent", "supervisor"). Empty string means unroled (full mesh). |
app_id | string | optional | Application identifier for event stream filtering. |
sip_headers | object | optional | Deprecated: X-* headers from the inbound INVITE. Only present on sip_inbound legs. Use `headers` for new code; it carries the same map plus surfaces handshake headers for websocket legs. |
headers | object | optional | Custom protocol headers exposed by the leg's transport — X-/P- headers from a SIP INVITE, the WebSocket upgrade request, or supplied at outbound dial time. |
custom_data | any | optional | Opaque application JSON attached to the leg. Any JSON value is accepted (object, array, string, number, boolean). It is echoed on the leg view and carried at the top level of every event published for this leg, so external state can be correlated without keeping a leg_id lookup table. Capped by CUSTOM_DATA_MAX_BYTES (default 1024 bytes, 0 = unlimited). |
| Field | Type | | Description |
|---|
websocket_url | string(uri) | required | WebSocket URL of the Pipecat bot (e.g. ws://my-bot:8765) |
| Field | Type | | Description |
|---|
url | string(uri) | required | URL of the audio file (mutually exclusive with tone) |
tone | string | required | Built-in telephone tone name. Format: {country}_{type} or bare {type} (defaults to US). Types: ringback, busy, dial, congestion. Countries: us, gb, de, fr, au, jp, it, in, br, pl, ru. Examples: us_ringback, gb_busy, dial. |
mime_type | string | required | MIME type (e.g. audio/wav). Required when using url. |
repeat | integer | required | Number of times to repeat playback (url only) 0 |
volume | integer | required | Volume adjustment in dB (-8 to 8) 0 |
| Field | Type | | Description |
|---|
storage | enum | required | "file" (default) — local disk, "s3" — upload to S3 after recording stops, "gcs" — upload to Google Cloud Storage via the native GCS API (Application Default Credentials / Workload Identity) Values: file, s3, gcs |
multi_channel | boolean | required | When true, record each participant to a separate mono WAV file in addition to the full mix. Only applies to room recordings. false |
s3_bucket | string | required | S3 bucket name. Overrides S3_BUCKET env var. Required if env var is not set. |
s3_region | string | required | AWS region. Overrides S3_REGION env var. Default us-east-1. |
s3_endpoint | string | required | Custom S3 endpoint (MinIO, etc.). Overrides S3_ENDPOINT env var. |
s3_prefix | string | required | Key prefix (e.g. recordings/). Overrides S3_PREFIX env var. |
s3_access_key | string | required | AWS access key ID. Overrides default credential chain. |
s3_secret_key | string | required | AWS secret access key. Must be set together with s3_access_key. |
gcs_bucket | string | required | GCS bucket name. Overrides GCS_BUCKET env var. Required if env var is not set when storage=gcs. |
gcs_object_name_prefix | string | required | Object name prefix (e.g. recordings or recordings/). Overrides GCS_OBJECT_NAME_PREFIX env var. A trailing slash is added automatically when missing. |
filename | string | required | Optional output basename for the WAV file. A .wav suffix is added when missing. Must be a single path segment (no directories). Dots inside the name are preserved (only a trailing .wav is treated as the extension). Rejected with 409 if the file already exists or another recording is using the same name. When omitted, a timestamped name is generated. |
| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
id | string | required | Room identifier |
app_id | string | optional | Application identifier for event stream filtering. |
sample_rate | integer | required | Mixer sample rate in Hz (8000, 16000, or 48000). |
participants | array[object] | required | Legs currently in this room |
| Field | Type | | Description |
|---|
id | string | required | Custom room ID (auto-generated UUID if omitted) |
webhook_url | string(uri) | optional | Route all events for this room exclusively to this URL instead of global webhooks. |
webhook_secret | string | optional | HMAC-SHA256 signing secret for the per-room webhook. |
app_id | string | optional | Application identifier. Carried through to all events for this room. Use to filter the WebSocket event stream by app. |
sample_rate | enum | optional | Mixer sample rate in Hz. Allowed values: 8000, 16000, 48000. Default: 16000. 16000Values: 8000, 16000, 48000 |
| Field | Type | | Description |
|---|
matrix | object | required | Listener-role → list of allowed source roles. Omitted listener roles default to full mesh. Empty list = hears nothing. |
| Field | Type | | Description |
|---|
updates | array[object] | required | Per-listener-role row replacements applied as a single atomic update. |
| Field | Type | | Description |
|---|
matrix | object | required | Listener-role → list of allowed source roles. Roles absent from the matrix default to full mesh. |
| Field | Type | | Description |
|---|
listener_role | string | required | The role whose row is being replaced. |
sources | array[string] | required | New list of allowed source roles for this listener role. Pass null to clear the row (full mesh). |
| Field | Type | | Description |
|---|
language | string | required | Language code (e.g. "en", "es") |
partial | boolean | required | Emit partial (non-final) transcripts false |
provider | enum | optional | STT provider: "elevenlabs" (default), "deepgram" (/v1/listen), "deepgram_flux" (/v2/listen, conversational turn detection), "azure" or "speechmatics" Values: elevenlabs, deepgram, deepgram_flux, azure, speechmatics |
api_key | string | optional | API key override (falls back to ELEVENLABS_API_KEY, DEEPGRAM_API_KEY, AZURE_SPEECH_KEY or SPEECHMATICS_API_KEY env var depending on provider) |
model | string | optional | Provider-specific model. Deepgram: default "nova-3". Deepgram Flux: "flux-general-en" (default) or "flux-general-multi". Speechmatics: "standard" (default) or "enhanced". |
keyterms | array[string] | optional | Terms to boost recognition of (Deepgram, Deepgram Flux, and Speechmatics — where they become additional_vocab). |
endpointing | integer | optional | Deepgram: milliseconds of silence before a segment is finalized; 0 disables endpointing. Speechmatics: maps to max_delay, clamped to 700-4000 ms; 0 leaves the provider default. |
utterance_end_ms | integer | optional | Deepgram: milliseconds of silence after which an stt.turn event with event=utterance_end is emitted. Deepgram requires interim results for this, which are requested automatically and still suppressed unless partial is true. Speechmatics: milliseconds of silence that close a turn and emit an stt.turn event with event=end_of_turn — default 600, capped at 2000, and 0 disables turn detection. |
eager_eot_threshold | number | optional | Deepgram Flux only: end-of-turn confidence that fires an eager_end_of_turn stt.turn event, enabling speculative generation. Must be between 0.3 and 0.9. When unset, no eager_end_of_turn or turn_resumed events are emitted at all. |
eot_threshold | number | optional | Deepgram Flux only: end-of-turn confidence required to close a turn. Deepgram default 0.7. |
eot_timeout_ms | integer | optional | Deepgram Flux only: milliseconds of silence after which a turn is closed regardless of confidence. Deepgram default 5000. |
language_hints | array[string] | optional | Deepgram Flux only: candidate language codes for the "flux-general-multi" model. |
| Field | Type | | Description |
|---|
srs_uri | string | required | SIP URI of the session recording server, e.g. "sip:srs@recorder.example.com:5060;transport=tcp". A recording session carries the metadata document alongside the SDP and exceeds the UDP message limit, so the target should accept TCP. The transport comes from the URI: ";transport=tcp", or "sips:" / ";transport=tls" for TLS. |
leg_ids | array[string] | optional | Which participants to record. Each entry is either a leg ID (that leg's own audio) or "<legID>#<streamID>" for one of a leg's secondary audio streams mixed into the room. Empty or absent records every participant. An entry that is not in the room is a 404. |
session_id | string | optional | Communication session identifier put in the recording metadata. Defaults to the room ID. |
app_id | string | optional | Application identifier tagged onto the resulting leg and its events. |
auth_username | string | optional | SIP digest username, when the recording server challenges the INVITE. |
auth_password | string | optional | SIP digest password, when the recording server challenges the INVITE. |
headers | object | optional | Extra SIP headers to include in the INVITE. Require: siprec is always sent. |
| Field | Type | | Description |
|---|
instance_id | string | optional | Instance identifier |
status | string | required | |
| Field | Type | | Description |
|---|
text | string | required | Text to synthesize |
voice | string | required | Provider-specific voice identifier. ElevenLabs: voice name or ID. AWS Polly: voice ID (e.g. Joanna, Matthew). Google Cloud: voice name — either full format (e.g. en-US-Neural2-F) or short name for Gemini models (e.g. Achernar, Kore). Deepgram: model name (e.g. aura-2-asteria-en). |
model_id | string | required | Provider-specific model/engine. ElevenLabs: model ID. AWS Polly: engine (standard, neural, long-form, generative; default neural). Google Cloud: model name (e.g. gemini-2.5-pro-tts, chirp3-hd). |
language | string | optional | Language code (e.g. "en-US", "pl-pl"). Required for Google Gemini TTS voices that use short names (e.g. Achernar). Auto-extracted from full voice names like en-US-Neural2-F. |
prompt | string | optional | Style/tone instruction for promptable voice models (Google Gemini TTS only). E.g. "Read aloud in a warm, welcoming tone." |
volume | integer | required | Volume adjustment in dB (-8 to 8) 0 |
provider | enum | optional | TTS provider: "elevenlabs" (default), "aws", "google", or "deepgram" Values: elevenlabs, aws, google, deepgram |
api_key | string | optional | ElevenLabs: API key override (falls back to ELEVENLABS_API_KEY env var). AWS: optional ACCESS_KEY:SECRET_KEY override (falls back to default AWS credential chain). Google Cloud: optional API key override (falls back to Application Default Credentials). Deepgram: API key override (falls back to DEEPGRAM_API_KEY env var). |
| Field | Type | | Description |
|---|
direction | enum | required | New audio flow relative to the room in the path: bidirectional, send, receive, or none. Values: bidirectional, send, receive, none |
| Field | Type | | Description |
|---|
assistant_id | string | required | VAPI assistant ID |
first_message | string | optional | Override the agent's first message |
variable_values | object | optional | Key-value pairs passed as VAPI variable values (assistantOverrides.variableValues) |
api_key | string | optional | API key override (falls back to VAPI_API_KEY env var) |
| Field | Type | | Description |
|---|
volume | integer | required | Volume adjustment (-8 to 8, ~3dB per step, 0 = unchanged) |