openapi: 3.1.0 info: title: Sayna API description: Real-time voice processing server with Speech-to-Text (STT) and Text-to-Speech (TTS) services contact: name: Sayna url: https://api.sayna.ai license: name: Apache-2.0 identifier: Apache-2.0 version: 0.1.0 servers: - url: https://api.sayna.ai description: Production API - url: http://localhost:3001 description: Local development paths: /: get: tags: - health summary: |- Health check handler Returns a simple JSON response indicating the server is running operationId: health_check responses: '200': description: Server is healthy content: application/json: schema: $ref: '#/components/schemas/HealthResponse' /livekit/participant: delete: tags: - livekit summary: Handler for DELETE /livekit/participant endpoint description: |- Removes a participant from a LiveKit room, forcibly disconnecting them. Access is authorized via `metadata.auth_id` check. Note: This does not invalidate the participant's token. To prevent rejoining, use short-lived tokens and avoid issuing new tokens to removed participants. # Arguments * `state` - Shared application state containing LiveKit configuration * `auth` - Authentication context from middleware * `request` - Request with room name and participant identity # Returns * `Response` - JSON response with removal status or error # Authorization - When `auth.id` is present: Requires `room.metadata.auth_id == auth.id` - When `auth.id` is absent: Access is allowed (backward-compatible mode) # Errors * 400 Bad Request - Empty room name or participant identity * 404 Not Found - Room/participant not found or access denied (masked) * 500 Internal Server Error - LiveKit not configured or removal failed # Flow 1. Validate request fields are not empty 2. Check room access via metadata.auth_id 3. Verify participant exists in the room 4. Remove the participant 5. Return success or appropriate error operationId: remove_participant requestBody: content: application/json: schema: $ref: '#/components/schemas/RemoveParticipantRequest' required: true responses: '200': description: Participant removed successfully content: application/json: schema: $ref: '#/components/schemas/RemoveParticipantResponse' '400': description: Invalid request (empty fields) content: application/json: schema: $ref: '#/components/schemas/RemoveParticipantErrorResponse' '404': description: Participant not found in room content: application/json: schema: $ref: '#/components/schemas/RemoveParticipantErrorResponse' '500': description: LiveKit not configured or removal failed content: application/json: schema: $ref: '#/components/schemas/RemoveParticipantErrorResponse' security: - auth: [] /livekit/participant/mute: post: tags: - livekit summary: Handler for POST /livekit/participant/mute endpoint description: |- Mutes or unmutes a participant's published track. Access is authorized via `metadata.auth_id` check. # Arguments * `state` - Shared application state containing LiveKit configuration * `auth` - Authentication context from middleware * `request` - Request with room name, participant identity, track_sid, and muted state # Returns * `Response` - JSON response with mute status or error # Authorization - When `auth.id` is present: Requires `room.metadata.auth_id == auth.id` - When `auth.id` is absent: Access is allowed (backward-compatible mode) # Errors * 400 Bad Request - Empty fields in request * 404 Not Found - Room/participant not found or access denied (masked) * 500 Internal Server Error - LiveKit not configured or mute operation failed operationId: mute_participant requestBody: content: application/json: schema: $ref: '#/components/schemas/MuteParticipantRequest' required: true responses: '200': description: Track muted/unmuted successfully content: application/json: schema: $ref: '#/components/schemas/MuteParticipantResponse' '400': description: Invalid request (empty fields) content: application/json: schema: $ref: '#/components/schemas/RemoveParticipantErrorResponse' '404': description: Room or participant not found content: application/json: schema: $ref: '#/components/schemas/RemoveParticipantErrorResponse' '500': description: LiveKit not configured or mute failed content: application/json: schema: $ref: '#/components/schemas/RemoveParticipantErrorResponse' security: - auth: [] /livekit/rooms: get: tags: - livekit summary: Handler for GET /livekit/rooms endpoint description: |- Lists all LiveKit rooms belonging to the authenticated client. Rooms are filtered by `metadata.auth_id` for tenant isolation. # Arguments * `state` - Shared application state containing LiveKit configuration * `auth` - Authentication context from middleware # Returns * `Response` - JSON response with rooms list or error status # Filtering - When `auth.id` is present: Returns only rooms where `metadata.auth_id == auth.id` - When `auth.id` is absent: Returns all rooms (backward-compatible mode) # Errors * 500 Internal Server Error - LiveKit service not configured or API call failed operationId: list_rooms responses: '200': description: Rooms listed successfully content: application/json: schema: $ref: '#/components/schemas/ListRoomsResponse' '500': description: LiveKit service not configured or failed to list rooms security: - auth: [] /livekit/rooms/{room_name}: get: tags: - livekit summary: Handler for GET /livekit/rooms/{room_name} endpoint description: |- Returns detailed information about a specific LiveKit room including all current participants. Access is authorized via `metadata.auth_id` check. # Arguments * `state` - Shared application state containing LiveKit configuration * `auth` - Authentication context from middleware * `room_name` - Name of the room to retrieve (from path parameter) # Returns * `Response` - JSON response with room details or error status # Authorization - When `auth.id` is present: Requires `room.metadata.auth_id == auth.id` - When `auth.id` is absent: Access is allowed (backward-compatible mode) # Errors * 404 Not Found - Room not found or access denied (masked as not found) * 500 Internal Server Error - LiveKit service not configured or API call failed operationId: get_room_details parameters: - name: room_name in: path description: Name of the room to retrieve required: true schema: type: string responses: '200': description: Room details retrieved successfully content: application/json: schema: $ref: '#/components/schemas/RoomDetailsResponse' '404': description: Room not found or not accessible '500': description: LiveKit service not configured or failed to get room details security: - auth: [] /livekit/token: post: tags: - livekit summary: Handler for POST /livekit/token endpoint description: |- Generates a LiveKit JWT token for a participant to join a specific room. When authentication is enabled (`auth.id` is present), this handler: 1. Creates the room if it doesn't exist 2. Sets `room.metadata.auth_id` to the authenticated tenant's ID 3. Issues the token only after metadata is verified/set # Arguments * `state` - Shared application state containing LiveKit configuration * `request` - Token request with room name and participant details # Returns * `Response` - JSON response with token or error status # Errors * 400 Bad Request - Invalid request data (empty fields) * 403 Forbidden - Room exists with a different tenant's `auth_id` * 500 Internal Server Error - LiveKit service not configured, room creation failed, or token generation failed operationId: generate_token requestBody: content: application/json: schema: $ref: '#/components/schemas/TokenRequest' required: true responses: '200': description: Token generated successfully. Room is created if it doesn't exist and metadata.auth_id is set. content: application/json: schema: $ref: '#/components/schemas/TokenResponse' '400': description: Invalid request (missing or empty fields) '403': description: 'Access denied: room exists with a different tenant''s auth_id' '500': description: LiveKit service not configured, room creation failed, or token generation failed security: - auth: [] /recording/{stream_id}: get: tags: - recordings summary: Download recording by stream ID from configured object storage operationId: download_recording parameters: - name: stream_id in: path description: Recording stream identifier required: true schema: type: string example: 550e8400-e29b-41d4-a716-446655440000 responses: '200': description: Recording retrieved successfully headers: Content-Disposition: schema: type: string description: Suggested filename for download Content-Length: schema: type: integer format: int64 minimum: 0 description: Size of the recording in bytes content: audio/ogg: {} '400': description: Invalid stream_id format '404': description: Recording not found '503': description: Recording storage not configured or unavailable security: - auth: [] /sip/call: post: tags: - sip summary: Handler for POST /sip/call endpoint description: Initiates an outbound SIP call through LiveKit. The optional `sip` object in the request body allows overriding global SIP configuration on a per-request basis. Request body values take priority over global config, enabling different SIP providers or credentials for specific calls. operationId: sip_call requestBody: content: application/json: schema: $ref: '#/components/schemas/SIPCallRequest' required: true responses: '200': description: Call initiated successfully content: application/json: schema: $ref: '#/components/schemas/SIPCallResponse' '400': description: Invalid request (bad phone number or empty fields) content: application/json: schema: $ref: '#/components/schemas/SIPCallErrorResponse' '404': description: Room not found or not accessible content: application/json: schema: $ref: '#/components/schemas/SIPCallErrorResponse' '500': description: LiveKit not configured, outbound address missing, or call failed content: application/json: schema: $ref: '#/components/schemas/SIPCallErrorResponse' security: - auth: [] /sip/hooks: get: tags: - sip summary: Lists all configured SIP hooks. description: |- Returns the current list of SIP hooks from runtime state. This endpoint requires authentication if `AUTH_REQUIRED=true`. # Returns * `200 OK` - List of SIP hooks * `500 Internal Server Error` - If reading the cache fails operationId: list_sip_hooks responses: '200': description: List of SIP hooks content: application/json: schema: $ref: '#/components/schemas/SipHooksResponse' '500': description: Failed to read hooks cache content: application/json: schema: $ref: '#/components/schemas/SipHooksErrorResponse' security: - auth: [] post: tags: - sip summary: Updates SIP hooks. description: |- Adds or replaces SIP hooks in the cache. Hooks with matching hosts (case-insensitive) will be replaced. Hosts defined in the application configuration cannot be modified. The changes take effect immediately and persist across server restarts. **Note**: Secrets are NOT stored in the cache. Runtime-added hooks will use the global `hook_secret` from the server configuration. # Request Body Array of hook entries with `host` and `url` fields. # Returns * `200 OK` - Updated list of SIP hooks * `400 Bad Request` - If validation fails (e.g., duplicate hosts) * `500 Internal Server Error` - If writing the cache fails operationId: update_sip_hooks requestBody: content: application/json: schema: $ref: '#/components/schemas/SipHooksRequest' required: true responses: '200': description: Updated list of SIP hooks content: application/json: schema: $ref: '#/components/schemas/SipHooksResponse' '400': description: Validation error content: application/json: schema: $ref: '#/components/schemas/SipHooksErrorResponse' '405': description: Host defined in application config cannot be modified content: application/json: schema: $ref: '#/components/schemas/SipHooksErrorResponse' '500': description: Failed to write hooks cache content: application/json: schema: $ref: '#/components/schemas/SipHooksErrorResponse' security: - auth: [] delete: tags: - sip summary: Deletes SIP hooks by host name. description: |- Removes the specified hosts from the cache. Hosts defined in the application configuration cannot be removed. If a host exists in the original server configuration, it will revert to its config value after deletion of a cached override. Hosts that only exist in cache will be completely removed. The changes take effect immediately and persist across server restarts. # Request Body Array of host names to remove (case-insensitive). # Returns * `200 OK` - Updated list of SIP hooks after deletion * `400 Bad Request` - If the hosts array is empty * `500 Internal Server Error` - If writing the cache fails operationId: delete_sip_hooks requestBody: content: application/json: schema: $ref: '#/components/schemas/DeleteSipHooksRequest' required: true responses: '200': description: Updated list of SIP hooks after deletion content: application/json: schema: $ref: '#/components/schemas/SipHooksResponse' '400': description: Validation error content: application/json: schema: $ref: '#/components/schemas/SipHooksErrorResponse' '405': description: Host defined in application config cannot be modified content: application/json: schema: $ref: '#/components/schemas/SipHooksErrorResponse' '500': description: Failed to write hooks cache content: application/json: schema: $ref: '#/components/schemas/SipHooksErrorResponse' security: - auth: [] /sip/transfer: post: tags: - sip summary: Handler for POST /sip/transfer endpoint description: |- Initiates a SIP REFER transfer for a participant in a LiveKit room. The transfer moves an ongoing SIP call to a different phone number. # Arguments * `state` - Shared application state containing LiveKit handlers * `auth` - Authentication context for room metadata authorization * `request` - Transfer request with room name, participant identity, and destination # Returns * `Response` - JSON response with transfer status or error # Errors * 400 Bad Request - Invalid phone number format or empty fields * 404 Not Found - Room not found, not accessible, or participant not found * 500 Internal Server Error - LiveKit not configured or transfer operation failed # Flow 1. Validate the phone number format 2. Check LiveKit handlers are configured 3. Check room access via metadata auth_id 4. Verify the participant exists and is a SIP participant 5. Execute the SIP transfer 6. Return success or appropriate error operationId: sip_transfer requestBody: content: application/json: schema: $ref: '#/components/schemas/SIPTransferRequest' required: true responses: '200': description: Transfer initiated successfully content: application/json: schema: $ref: '#/components/schemas/SIPTransferResponse' '400': description: Invalid request (bad phone number or empty fields) content: application/json: schema: $ref: '#/components/schemas/SIPTransferErrorResponse' '404': description: Room not found, not accessible, or participant not found content: application/json: schema: $ref: '#/components/schemas/SIPTransferErrorResponse' '500': description: LiveKit not configured or transfer failed content: application/json: schema: $ref: '#/components/schemas/SIPTransferErrorResponse' security: - auth: [] /speak: post: tags: - tts summary: Handler for the /speak endpoint operationId: speak_handler requestBody: content: application/json: schema: $ref: '#/components/schemas/SpeakRequest' required: true responses: '200': description: Audio generated successfully headers: x-audio-format: schema: type: string description: Audio format (linear16, mp3, etc.) x-sample-rate: schema: type: integer format: int32 minimum: 0 description: Sample rate in Hz content: audio/pcm: {} '400': description: Invalid request (empty text) '500': description: TTS synthesis failed security: - auth: [] /voices: get: tags: - voices summary: Handler for GET /voices - returns available voices per provider operationId: list_voices responses: '200': description: Available voices grouped by provider content: application/json: schema: type: object additionalProperties: type: array items: $ref: '#/components/schemas/Voice' propertyNames: type: string '500': description: Internal server error security: - auth: [] components: schemas: DeleteSipHooksRequest: type: object description: |- Request body for deleting SIP hooks. Contains a list of host names to remove from the SIP hooks cache. properties: hosts: type: array items: type: string description: |- List of host names to remove (case-insensitive). Hosts that exist in the original config will revert to their config values. example: - example.com - other.com HealthResponse: type: object description: Health check response required: - status properties: status: type: string description: Server status example: OK IncomingMessage: oneOf: - type: object required: - type properties: audio: type: - boolean - 'null' description: Enable audio processing (STT/TTS). Defaults to true if not specified. livekit: oneOf: - type: 'null' - $ref: '#/components/schemas/LiveKitWebSocketConfig' description: Optional LiveKit configuration for real-time audio streaming loading_audio: oneOf: - type: 'null' - $ref: '#/components/schemas/LoadingAudioConfig' description: Optional loading-indicator audio configuration. stream_id: type: - string - 'null' description: |- Optional unique identifier for this WebSocket session. Used for recording paths and session tracking. If not provided, a UUID v4 will be auto-generated by the server. example: 550e8400-e29b-41d4-a716-446655440000 stt_config: oneOf: - type: 'null' - $ref: '#/components/schemas/STTWebSocketConfig' description: STT configuration (required only when audio=true) tts_config: oneOf: - type: 'null' - $ref: '#/components/schemas/TTSWebSocketConfig' description: TTS configuration (required only when audio=true) type: type: string enum: - config - type: object required: - text - type properties: allow_interruption: type: - boolean - 'null' description: Allow this TTS to be interrupted flush: type: - boolean - 'null' description: Flush TTS buffer immediately text: type: string description: Text to synthesize type: type: string enum: - speak - type: object required: - type properties: type: type: string enum: - clear - type: object required: - message - role - type properties: debug: description: Optional debug metadata message: type: string description: Message content role: type: string description: Message role (e.g., "user", "assistant") topic: type: - string - 'null' description: Optional topic/channel type: type: string enum: - send_message - type: object description: |- Transfer the current SIP call to another phone number. This command initiates a SIP REFER transfer for the current participant in the LiveKit room. The participant identity and room name are derived from the WebSocket connection state. required: - transfer_to - type properties: transfer_to: type: string description: |- The destination phone number to transfer the call to. Accepts phone numbers in various formats: - International format with `+` prefix (e.g., "+1234567890") - National format without prefix (e.g., "1234567890") - Internal extensions (e.g., "1234") Validation is performed by the handler, not during deserialization. example: '+1234567890' type: type: string enum: - sip_transfer - type: object description: |- Update runtime configuration for VAD and turn detection. This message allows dynamic adjustment of VAD and turn detection parameters during an active WebSocket session. Only parameters that are provided will be updated; omitted parameters retain their current values. **Note**: These settings affect the shared turn detector and may impact other active sessions using the same server instance. required: - type properties: turn_detect: oneOf: - type: 'null' - $ref: '#/components/schemas/TurnDetectConfigUpdate' description: Turn detection configuration updates (probability threshold) type: type: string enum: - update_config vad: oneOf: - type: 'null' - $ref: '#/components/schemas/VADConfigUpdate' description: VAD configuration updates (silence threshold, etc.) - type: object description: Begin looping the configured loading-indicator audio into the LiveKit room. required: - type properties: type: type: string enum: - loading_start - type: object description: Stop the loading-indicator audio loop (with a short fade-out). required: - type properties: type: type: string enum: - loading_stop description: WebSocket message types for incoming messages ListRoomsResponse: type: object description: |- Response containing the list of LiveKit rooms # Example ```json { "rooms": [ { "name": "room-1", "num_participants": 2, "creation_time": 1703123456 }, { "name": "room-2", "num_participants": 0, "creation_time": 1703123789 } ] } ``` required: - rooms properties: rooms: type: array items: $ref: '#/components/schemas/RoomInfo' description: List of rooms belonging to the authenticated client (filtered by metadata.auth_id) LiveKitWebSocketConfig: type: object description: LiveKit configuration for WebSocket messages required: - room_name properties: enable_recording: type: boolean description: Enable recording for this session listen_participants: type: array items: type: string description: |- List of participant identities to listen to for audio tracks and data messages. (All participants by default) **Behavior**: - If **empty** (default): Audio tracks and data messages from **all participants** will be processed - If **populated**: Only audio tracks and data messages from participants whose identities are in this list will be processed; others will be ignored room_name: type: string description: Room name to join or create example: conversation-room-123 sayna_participant_identity: type: - string - 'null' description: Sayna AI participant identity (defaults to "sayna-ai") example: sayna-ai sayna_participant_name: type: - string - 'null' description: Sayna AI participant display name (defaults to "Sayna AI") example: Sayna AI LoadingAudioConfig: type: object description: Loading-indicator audio configuration supplied in the `config` message. required: - data properties: channels: type: - integer - 'null' format: int32 description: Channel count for raw PCM (1 = mono, 2 = stereo); defaults to 1. Ignored for WAV. example: 1 minimum: 0 data: type: string description: Base64-encoded audio bytes — a complete WAV file or raw 16-bit PCM. format: type: - string - 'null' description: 'Audio format: "wav" or "pcm". If omitted, the server auto-detects.' example: wav sample_rate: type: - integer - 'null' format: int32 description: Sample rate in Hz. Required for raw PCM; ignored for WAV (header is authoritative). example: 16000 minimum: 0 volume: type: - number - 'null' format: float description: Playback volume from 0.0 (silent) to 1.0 (authored level). Default 1.0; out-of-range clamped. example: 0.3 MuteParticipantRequest: type: object description: |- Request body for muting/unmuting a participant's track # Example ```json { "room_name": "conversation-room-123", "participant_identity": "user-alice-456", "track_sid": "TR_abc123", "muted": true } ``` required: - room_name - participant_identity - track_sid - muted properties: muted: type: boolean description: True to mute, false to unmute example: true participant_identity: type: string description: The identity of the participant whose track to mute example: user-alice-456 room_name: type: string description: The LiveKit room name where the participant is connected example: conversation-room-123 track_sid: type: string description: The session ID of the track to mute/unmute example: TR_abc123 MuteParticipantResponse: type: object description: |- Response for a successful mute/unmute operation # Example ```json { "room_name": "conversation-room-123", "participant_identity": "user-alice-456", "track_sid": "TR_abc123", "muted": true } ``` required: - room_name - participant_identity - track_sid - muted properties: muted: type: boolean description: Current muted state example: true participant_identity: type: string description: The identity of the participant example: user-alice-456 room_name: type: string description: The room name example: conversation-room-123 track_sid: type: string description: The session ID of the track example: TR_abc123 OutgoingMessage: oneOf: - type: object required: - stream_id - type properties: livekit_room_name: type: - string - 'null' description: Optional LiveKit room name that was created livekit_url: type: - string - 'null' description: Optional LiveKit URL to connect to sayna_participant_identity: type: - string - 'null' description: Optional identity of the AI agent participant in the room sayna_participant_name: type: - string - 'null' description: Optional display name of the AI agent participant stream_id: type: string description: |- Unique identifier for this WebSocket session. Either provided by the client in config or auto-generated by server (UUID v4). example: 550e8400-e29b-41d4-a716-446655440000 type: type: string enum: - ready - type: object required: - transcript - is_final - is_speech_final - confidence - type properties: confidence: type: number format: float description: Confidence score (0.0 to 1.0) is_final: type: boolean description: Whether this is the final version of the transcript is_speech_final: type: boolean description: Whether speech has ended transcript: type: string description: Transcribed text type: type: string enum: - stt_result - type: object required: - message - type properties: message: $ref: '#/components/schemas/UnifiedMessage' description: Unified message structure containing text/data from various sources type: type: string enum: - message - type: object required: - participant - type properties: participant: $ref: '#/components/schemas/ParticipantConnectedInfo' description: Information about the participant who connected type: type: string enum: - participant_connected - type: object required: - participant - type properties: participant: $ref: '#/components/schemas/ParticipantDisconnectedInfo' description: Information about the participant who disconnected type: type: string enum: - participant_disconnected - type: object description: |- Track subscription notification Emitted when Sayna subscribes to a participant's track in the LiveKit room. This indicates that Sayna has started processing the participant's media. required: - track - type properties: track: $ref: '#/components/schemas/TrackSubscribedInfo' description: Information about the subscribed track type: type: string enum: - track_subscribed - type: object description: TTS playback completion notification required: - timestamp - type properties: timestamp: type: integer format: int64 description: Timestamp when completion occurred (milliseconds since epoch) minimum: 0 type: type: string enum: - tts_playback_complete - type: object description: |- VAD event notification Emitted when VAD detects speech activity changes: - `speech_start`: User started speaking - `silence_detected`: Brief silence detected - `speech_resumed`: User resumed speaking after brief silence - `turn_end`: Silence exceeded threshold, turn complete required: - event - timestamp_ms - type properties: event: type: string description: 'Event type: "speech_start", "silence_detected", "speech_resumed", "turn_end"' example: turn_end silence_duration_ms: type: - integer - 'null' format: int64 description: Silence duration in milliseconds (only present for silence_detected and turn_end events) minimum: 0 timestamp_ms: type: integer format: int64 description: Timestamp when the event occurred (milliseconds since epoch) example: 1704067200000 minimum: 0 type: type: string enum: - vad_event - type: object required: - message - type properties: message: type: string description: Error message type: type: string enum: - error - type: object description: |- SIP transfer specific error This message is sent when a SIP transfer operation fails. Clients can subscribe to this specific error type to handle SIP transfer failures separately from other errors. required: - message - type properties: message: type: string description: Error message describing why the transfer failed type: type: string enum: - sip_transfer_error description: WebSocket message types for outgoing messages ParticipantConnectedInfo: type: object description: Participant connection information required: - identity - room - timestamp properties: identity: type: string description: Participant's unique identity name: type: - string - 'null' description: Participant's display name (if available) room: type: string description: Room identifier timestamp: type: integer format: int64 description: Timestamp when the connection occurred minimum: 0 ParticipantDisconnectedInfo: type: object description: Participant disconnection information required: - identity - room - timestamp properties: identity: type: string description: Participant's unique identity name: type: - string - 'null' description: Participant's display name (if available) room: type: string description: Room identifier timestamp: type: integer format: int64 description: Timestamp when the disconnection occurred minimum: 0 ParticipantInfo: type: object description: |- Detailed information about a participant in a LiveKit room # Example ```json { "sid": "PA_abc123", "identity": "user-alice-456", "name": "Alice Smith", "state": "ACTIVE", "kind": "STANDARD", "joined_at": 1703123456, "metadata": "{\"role\": \"host\"}", "attributes": {} } ``` required: - sid - identity - name - state - kind - joined_at - metadata - attributes - is_publisher properties: attributes: type: object description: User-specified attributes for the participant additionalProperties: type: string propertyNames: type: string identity: type: string description: Unique identifier provided when connecting example: user-alice-456 is_publisher: type: boolean description: Whether the participant is currently publishing audio/video example: true joined_at: type: integer format: int64 description: Timestamp when participant joined (Unix timestamp in seconds) example: 1703123456 kind: type: string description: 'Participant kind: STANDARD, AGENT, SIP, EGRESS, or INGRESS' example: STANDARD metadata: type: string description: User-specified metadata for the participant example: role: host name: type: string description: Display name of the participant example: Alice Smith sid: type: string description: Unique session ID for this participant (generated by LiveKit) example: PA_abc123 state: type: string description: 'Participant state: JOINING, JOINED, ACTIVE, or DISCONNECTED' example: ACTIVE Pronunciation: type: object description: Pronunciation replacement configuration required: - word - pronunciation properties: pronunciation: type: string description: Pronunciation to use instead example: A P I word: type: string description: Word to replace example: API ProviderAuthInput: allOf: - type: object description: Provider-specific auth fields. description: |- Raw provider auth input received from API callers. The outer provider field determines how these fields are interpreted. RemoveParticipantErrorResponse: type: object description: |- Error response for participant removal failures # Example ```json { "error": "Participant 'user-123' not found in room", "code": "PARTICIPANT_NOT_FOUND" } ``` required: - error - code properties: code: type: string description: Machine-readable error code example: PARTICIPANT_NOT_FOUND error: type: string description: Human-readable error message example: Participant not found in room RemoveParticipantRequest: type: object description: |- Request body for removing a participant from a LiveKit room # Example ```json { "room_name": "conversation-room-123", "participant_identity": "user-alice-456" } ``` required: - room_name - participant_identity properties: participant_identity: type: string description: The identity of the participant to remove example: user-alice-456 room_name: type: string description: The LiveKit room name where the participant is connected example: conversation-room-123 RemoveParticipantResponse: type: object description: |- Response for a successful participant removal # Example ```json { "status": "removed", "room_name": "conversation-room-123", "participant_identity": "user-alice-456" } ``` required: - status - room_name - participant_identity properties: participant_identity: type: string description: The identity of the removed participant example: user-alice-456 room_name: type: string description: The room name example: conversation-room-123 status: type: string description: Status of the removal operation example: removed RoomDetailsResponse: type: object description: |- Detailed information about a LiveKit room including participants # Example ```json { "sid": "RM_xyz789", "name": "conversation-room-123", "num_participants": 2, "max_participants": 10, "creation_time": 1703123456, "metadata": "{\"auth_id\": \"tenant-123\"}", "active_recording": false, "participants": [...] } ``` required: - sid - name - num_participants - max_participants - creation_time - metadata - active_recording - participants properties: active_recording: type: boolean description: Whether a recording is currently active example: false creation_time: type: integer format: int64 description: Room creation time (Unix timestamp in seconds) example: 1703123456 max_participants: type: integer format: int32 description: Maximum allowed participants (0 = no limit) example: 10 minimum: 0 metadata: type: string description: User-specified metadata for the room example: '' name: type: string description: The room name example: conversation-room-123 num_participants: type: integer format: int32 description: Number of current participants in the room example: 2 minimum: 0 participants: type: array items: $ref: '#/components/schemas/ParticipantInfo' description: List of participants currently in the room sid: type: string description: Unique session ID for the room (generated by LiveKit) example: RM_xyz789 RoomInfo: type: object description: |- Information about a LiveKit room # Example ```json { "name": "conversation-room-123", "num_participants": 2, "creation_time": 1703123456 } ``` required: - name - num_participants - creation_time properties: creation_time: type: integer format: int64 description: Room creation time (Unix timestamp in seconds) example: 1703123456 name: type: string description: The room name example: conversation-room-123 num_participants: type: integer format: int32 description: Number of current participants in the room example: 2 minimum: 0 SIPCallErrorResponse: type: object description: |- Error response for SIP call failures # Example ```json { "error": "Outbound address not configured", "code": "OUTBOUND_ADDRESS_NOT_CONFIGURED" } ``` required: - error - code properties: code: type: string description: Machine-readable error code example: OUTBOUND_ADDRESS_NOT_CONFIGURED error: type: string description: Human-readable error message example: Outbound address not configured SIPCallRequest: type: object description: |- Request body for initiating an outbound SIP call # Example ```json { "room_name": "call-room-123", "participant_name": "John Doe", "participant_identity": "caller-456", "from_phone_number": "+15105550123", "to_phone_number": "+15551234567", "sip": { "outbound_address": "sip.provider.com", "auth_username": "user123", "auth_password": "secret" } } ``` # SIP Configuration Priority The `sip` object is optional. When provided, its fields take priority over global server configuration values. This allows per-request customization of SIP settings. **Priority order**: Request body `sip` config > Global server config - `outbound_address`: Overrides `sip.outbound_address` from config - `auth_username`: Overrides `sip.outbound_auth_username` from config - `auth_password`: Overrides `sip.outbound_auth_password` from config If neither the request body nor global config provides an `outbound_address`, the call will fail with `OUTBOUND_ADDRESS_NOT_CONFIGURED` error. required: - room_name - participant_name - participant_identity - from_phone_number - to_phone_number properties: from_phone_number: type: string description: |- Phone number the call will originate from. Must be configured in your SIP provider. Supports international format (+1234567890). example: '+15105550123' participant_identity: type: string description: Identity for the SIP participant in the room example: caller-456 participant_name: type: string description: Display name for the SIP participant in the room example: John Doe room_name: type: string description: The LiveKit room name to connect the call to example: call-room-123 sip: oneOf: - type: 'null' - $ref: '#/components/schemas/SIPCallSipConfig' description: |- Optional per-request SIP configuration overrides. When provided, these values take priority over the global server configuration. This allows using different SIP providers or credentials for specific calls. to_phone_number: type: string description: |- Phone number to dial. Supports international format (+1234567890), national format (07123456789), or extensions (1234). example: '+15551234567' SIPCallResponse: type: object description: |- Response for a successful SIP call initiation # Example ```json { "status": "initiated", "room_name": "call-room-123", "participant_identity": "caller-456", "participant_id": "PA_abc123", "sip_call_id": "SC_xyz789" } ``` required: - status - room_name - participant_identity - participant_id - sip_call_id properties: participant_id: type: string description: The unique participant ID assigned by LiveKit example: PA_abc123 participant_identity: type: string description: The identity of the SIP participant in the room example: caller-456 room_name: type: string description: The room name where the call was connected example: call-room-123 sip_call_id: type: string description: The unique SIP call ID for tracking example: SC_xyz789 status: type: string description: Status of the call request ("initiated") example: initiated SIPCallSipConfig: type: object description: |- Per-request SIP configuration overrides Allows overriding the global SIP configuration on a per-request basis. When specified, these values take priority over the global server configuration. # Priority Request body values > Global config values # Example ```json { "outbound_address": "sip.example.com:5060", "auth_username": "user123", "auth_password": "secret456" } ``` properties: auth_password: type: - string - 'null' description: |- SIP authentication password override. When provided, overrides the global `sip.outbound_auth_password` config. example: secure_password_456 auth_username: type: - string - 'null' description: |- SIP authentication username override. When provided, overrides the global `sip.outbound_auth_username` config. example: sip_user_123 outbound_address: type: - string - 'null' description: |- SIP server address override for outbound calls. When provided, overrides the global `sip.outbound_address` config. Format: hostname or hostname:port (e.g., "sip.example.com" or "sip.example.com:5060") example: sip.provider.com:5060 SIPTransferErrorResponse: type: object description: |- Error response for SIP transfer failures # Example ```json { "error": "Participant 'sip_123' not found or is not a SIP participant", "code": "PARTICIPANT_NOT_FOUND" } ``` required: - error - code properties: code: type: string description: Machine-readable error code example: PARTICIPANT_NOT_FOUND error: type: string description: Human-readable error message example: Participant not found or is not a SIP participant SIPTransferRequest: type: object description: |- Request body for initiating a SIP call transfer # Example ```json { "room_name": "call-room-123", "participant_identity": "sip_participant_456", "transfer_to": "+15551234567" } ``` required: - room_name - participant_identity - transfer_to properties: participant_identity: type: string description: |- The identity of the SIP participant to transfer. This can be obtained by listing participants in the room via LiveKit API. example: sip_participant_456 room_name: type: string description: The LiveKit room name where the SIP participant is connected example: call-room-123 transfer_to: type: string description: |- The phone number to transfer the call to. Supports international format (+1234567890), national format (07123456789), or internal extensions (1234). example: '+15551234567' SIPTransferResponse: type: object description: |- Response for a successful SIP transfer initiation Note: A successful response indicates the transfer has been initiated, not that it has completed. The actual transfer may take several seconds. # Example ```json { "status": "initiated", "room_name": "call-room-123", "participant_identity": "sip_participant_456", "transfer_to": "tel:+15551234567" } ``` required: - status - room_name - participant_identity - transfer_to properties: participant_identity: type: string description: The identity of the participant being transferred example: sip_participant_456 room_name: type: string description: The room name where the transfer was initiated example: call-room-123 status: type: string description: Status of the transfer request ("initiated" or "completed") example: initiated transfer_to: type: string description: 'The normalized phone number with tel: prefix' example: tel:+15551234567 STTWebSocketConfig: type: object description: STT configuration for WebSocket messages. required: - provider - language - sample_rate - channels - punctuation - encoding - model properties: auth: oneOf: - type: 'null' - $ref: '#/components/schemas/ProviderAuthInput' description: |- Optional provider auth override for this session. Examples by provider: - Deepgram / ElevenLabs / Cartesia: `{ "api_key": "..." }` - Google: `{ "credentials": "/path/to/creds.json" }` or `{ "credentials": { ...service account json... } }` - Azure: `{ "api_key": "...", "region": "eastus" }` channels: type: integer format: int32 description: Number of audio channels (1 for mono, 2 for stereo) example: 1 minimum: 0 encoding: type: string description: Encoding of the audio example: linear16 language: type: string description: Language code for transcription (e.g., "en-US", "es-ES") example: en-US model: type: string description: Model to use for transcription example: nova-2 provider: type: string description: Provider name (e.g., "deepgram") example: deepgram punctuation: type: boolean description: Enable punctuation in results example: true sample_rate: type: integer format: int32 description: Sample rate of the audio in Hz example: 16000 minimum: 0 SipHookEntry: type: object description: |- A single SIP hook entry. Note: The `auth_id` field is conditionally required based on `AUTH_REQUIRED`: - When `AUTH_REQUIRED=true`: `auth_id` must be provided and cannot be empty - When `AUTH_REQUIRED=false`: `auth_id` may be empty (unauthenticated mode) required: - host - url - auth_id properties: auth_id: type: string description: |- Tenant identifier for this hook (written to LiveKit room metadata). Required when AUTH_REQUIRED=true; may be empty when AUTH_REQUIRED=false. When empty, room metadata updates are skipped. example: tenant-123 host: type: string description: Host pattern for matching SIP domains (case-insensitive) example: example.com url: type: string description: HTTPS URL to forward webhook events to example: https://webhook.example.com/events SipHooksErrorResponse: type: object description: Error response for SIP hooks operations. required: - error properties: error: type: string description: Error message describing what went wrong example: 'Duplicate host detected: example.com' SipHooksRequest: type: object description: |- Request body for updating SIP hooks. Contains a list of SIP webhook configurations to add or replace. properties: hooks: type: array items: $ref: '#/components/schemas/SipHookEntry' description: |- List of SIP hooks to add or replace. Hooks with matching hosts (case-insensitive) will be replaced. SipHooksResponse: type: object description: Response body for SIP hooks operations. required: - hooks properties: hooks: type: array items: $ref: '#/components/schemas/SipHookEntry' description: List of all configured SIP hooks SpeakRequest: type: object description: Request body for the speak endpoint required: - text - tts_config properties: text: type: string description: The text to synthesize example: Hello, world! tts_config: $ref: '#/components/schemas/TTSWebSocketConfig' description: TTS configuration, including an optional provider auth override. TTSWebSocketConfig: type: object description: TTS configuration for WebSocket messages. required: - provider - model properties: audio_format: type: - string - 'null' description: Audio format preference example: linear16 auth: oneOf: - type: 'null' - $ref: '#/components/schemas/ProviderAuthInput' description: |- Optional provider auth override for this session or request. Examples by provider: - Deepgram / ElevenLabs / Cartesia: `{ "api_key": "..." }` - Google: `{ "credentials": "/path/to/creds.json" }` or `{ "credentials": { ...service account json... } }` - Azure: `{ "api_key": "...", "region": "eastus" }` connection_timeout: type: - integer - 'null' format: int64 description: Connection timeout in seconds example: 30 minimum: 0 model: type: string description: Model to use for TTS example: aura-asteria-en pronunciations: type: array items: $ref: '#/components/schemas/Pronunciation' description: Pronunciation replacements to apply before TTS provider: type: string description: Provider name (e.g., "deepgram") example: deepgram request_timeout: type: - integer - 'null' format: int64 description: Request timeout in seconds example: 60 minimum: 0 sample_rate: type: - integer - 'null' format: int32 description: Sample rate preference example: 24000 minimum: 0 speaking_rate: type: - number - 'null' format: float description: Speaking rate (0.25 to 4.0, 1.0 is normal) example: 1.0 voice_id: type: - string - 'null' description: Voice ID or name to use for synthesis example: aura-asteria-en TokenRequest: type: object description: |- Request body for generating a LiveKit token # Example ```json { "room_name": "conversation-room-123", "participant_name": "Alice Smith", "participant_identity": "user-alice-456" } ``` required: - room_name - participant_name - participant_identity properties: participant_identity: type: string description: Unique identifier for the participant (e.g., "user-123") example: user-alice-456 participant_name: type: string description: Display name for the participant (e.g., "John Doe") example: Alice Smith room_name: type: string description: The LiveKit room name to generate a token for example: conversation-room-123 TokenResponse: type: object description: |- Response containing the generated LiveKit token # Example ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "room_name": "conversation-room-123", "participant_identity": "user-alice-456", "livekit_url": "ws://localhost:7880" } ``` required: - token - room_name - participant_identity - livekit_url properties: livekit_url: type: string description: The LiveKit server URL to connect to example: ws://localhost:7880 participant_identity: type: string description: Echo back the participant identity for client confirmation example: user-alice-456 room_name: type: string description: Echo back the room name for client confirmation example: conversation-room-123 token: type: string description: The generated JWT token for LiveKit example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... TrackSubscribedInfo: type: object description: Track subscription information required: - identity - track_kind - track_sid - room - timestamp properties: identity: type: string description: Participant's unique identity (owner of the track) name: type: - string - 'null' description: Participant's display name (if available) room: type: string description: Room identifier timestamp: type: integer format: int64 description: Timestamp when the subscription occurred minimum: 0 track_kind: type: string description: 'Track kind: "audio" or "video"' track_sid: type: string description: Track SID (publication identifier) TurnDetectConfigUpdate: type: object description: Turn detection configuration update for runtime adjustments properties: threshold: type: - number - 'null' format: float description: |- Turn completion probability threshold (0.0 to 1.0). When the smart-turn model returns a probability >= this threshold, the turn is considered complete and speech_final is emitted. example: 0.5 UnifiedMessage: type: object description: Unified message structure for all incoming messages from various sources required: - identity - topic - room - timestamp properties: data: type: - string - 'null' description: Binary data encoded as base64 (optional) identity: type: string description: Participant/sender identity message: type: - string - 'null' description: Text message content (optional) room: type: string description: Room/space identifier timestamp: type: integer format: int64 description: Timestamp when the message was received minimum: 0 topic: type: string description: Topic/channel for the message VADConfigUpdate: type: object description: VAD configuration update for runtime adjustments properties: silence_duration_ms: type: - integer - 'null' format: int64 description: |- Silence duration threshold in milliseconds to trigger turn detection. When silence exceeds this duration, the smart-turn model is queried. example: 300 minimum: 0 Voice: type: object required: - id - sample - name - accent - gender - language properties: accent: type: string description: Accent or dialect example: American gender: type: string description: Gender of the voice example: Female id: type: string description: Voice ID or canonical name example: aura-asteria-en language: type: string description: Language supported by the voice example: English name: type: string description: Display name of the voice example: Asteria sample: type: string description: URL to sample audio example: https://example.com/sample.mp3 securitySchemes: auth: type: http scheme: bearer bearerFormat: Token description: 'Authentication token for protected endpoints. Can be provided as `Authorization: Bearer ` or `?api_key=`. Required when AUTH_REQUIRED is enabled.' tags: - name: health description: Health check endpoints - name: voices description: TTS voice management - name: tts description: Text-to-speech synthesis - name: livekit description: LiveKit room and token management - name: recordings description: Recording download operations - name: sip description: SIP webhook configuration management - name: websocket description: WebSocket API for real-time communication