Qwen-Audio-Realtime WebSocket connection protocol, request headers, core concepts, and interaction flows
The Qwen-Audio Realtime API provides real-time voice conversation over WebSocket. The client interacts with the server by sending and receiving JSON events, supporting voice input, text input, voice activity detection (VAD), and streaming voice and text output.
User guide: Real-time voice conversation (Qwen-Audio-Realtime). For details about client and server events, see Client events and Server events.
Use the following WebSocket URL. The
Include the following fields in the request headers:
The Qwen-Audio Realtime API supports three interaction modes, configured via the
For details about client and server events, see Client events and Server events.
The server performs voice activity detection on the incoming audio and automatically triggers inference once it detects the end of speech.
To enable: Set
In chronological order, the client and server interact as follows:
If VAD detects the user starting to speak while the model is playing back a response, the server cancels the current response (returning
Combines acoustic perception with semantic understanding to detect the end of speech, filtering out backchannels, background noise, and other non-meaningful sounds. Non-semantic sounds are passed through via the
Main differences from server_vad mode:
Interruption handling is largely the same as in server_vad mode:
Speech that was initially judged valid may later be retracted (
In smart_turn mode, when
The client manually controls audio submission and inference triggering. Suitable for push-to-talk scenarios.
To enable: Set
In chronological order, the client and server interact as follows:
The client sends
Service endpoint
Use the following WebSocket URL. The model query parameter specifies the model to call (replace <model_name> with the actual model name):
The URL must use the
wss:// scheme. Set authorization in the request headers; specify the model through the model query parameter.Request headers
Include the following fields in the request headers:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Authentication token in the format Bearer $DASHSCOPE_API_KEY. Replace $DASHSCOPE_API_KEY with your actual API key. |
| user-agent | string | No | Client identifier that helps the server track request sources. |
| X-DashScope-WorkSpace | string | No | QwenCloud workspace ID. |
Authorization is verified during the WebSocket handshake. If the API key is invalid or missing, the handshake fails with an HTTP 401 or 403 error.
Core concepts
- Session: Each WebSocket connection corresponds to one session, which maintains configuration and conversation context.
- Conversation item: Each message in the conversation, organized as a linked list in order.
- Response: The output produced by one round of model inference, containing one or more output items. An output item can be an assistant message or a function call.
- Function call: An output item produced when the model requests the client to execute a tool function. After execution, the client writes back the result via
function_call_outputand triggers the next round of inference withresponse.create. - Turn detection: Controls when inference is triggered.
Interaction modes
The Qwen-Audio Realtime API supports three interaction modes, configured via the turn_detection.type parameter in the session.update event:
| Mode | turn_detection.type | Description | Use case |
|---|---|---|---|
| server_vad | server_vad | The server uses VAD to detect the start and end of speech and automatically triggers inference. | Hands-free conversation, voice assistants |
| smart_turn | smart_turn | Combines acoustic perception with semantic understanding to determine turn boundaries, rather than relying only on voice signals. Non-semantic sounds (such as "um" or "uh") do not trigger a conversation turn or interrupt model playback. | Low-latency natural conversation, high-quality interruption |
| push-to-talk | null | The client manually submits audio and manually triggers inference. | Push-to-talk, precise control |
Interaction flows
For details about client and server events, see Client events and Server events.
server_vad mode
The server performs voice activity detection on the incoming audio and automatically triggers inference once it detects the end of speech.
To enable: Set turn_detection.type to server_vad in the session.update event.
A complete conversation turn
In chronological order, the client and server interact as follows:
- The client establishes a WebSocket connection; the server returns a
session.createdevent. - The client sends
session.updateto configure session parameters; the server returnssession.updated. - The client continuously sends
input_audio_buffer.appendevents to append audio data. - The server detects the start of speech and returns
input_audio_buffer.speech_started, while streaming incremental ASR transcription viaconversation.item.input_audio_transcription.delta. - The server detects the end of speech and returns
input_audio_buffer.speech_stopped,input_audio_buffer.committed, andconversation.item.created. - The server automatically generates a response, streaming text and audio deltas (
response.audio_transcript.delta,response.audio.delta), and finally returnsresponse.done.
| Phase | Direction | Event |
|---|---|---|
| Session initialization | Client -> Server | connect |
| Server -> Client | session.created | |
| Client -> Server | session.update | |
| Server -> Client | session.updated | |
| Voice input (loop) | Client -> Server | input_audio_buffer.append (sent continuously) |
| Server -> Client | input_audio_buffer.speech_started | |
| Client -> Server | input_audio_buffer.append (sent continuously) | |
| Server -> Client | conversation.item.input_audio_transcription.delta (streamed) | |
| Server -> Client | input_audio_buffer.speech_stopped | |
| Server -> Client | conversation.item.input_audio_transcription.completed | |
| Server (internal) | commit audio buffer | |
| Server -> Client | input_audio_buffer.committed | |
| Server -> Client | conversation.item.created | |
| Response generation | Server -> Client | response.created |
| Server -> Client | response.output_item.added | |
| Server -> Client | conversation.item.created | |
| Server -> Client | response.content_part.added | |
| Streaming output (loop) | Server -> Client | response.audio_transcript.delta (streamed) |
| Server -> Client | response.audio.delta (streamed) | |
| Output complete | Server -> Client | response.audio_transcript.done |
| Server -> Client | response.audio.done | |
| Server -> Client | response.content_part.done | |
| Server -> Client | response.output_item.done | |
| Server -> Client | response.done |
User interruption
If VAD detects the user starting to speak while the model is playing back a response, the server cancels the current response (returning response.done with status cancelled), then starts a new round of voice input and response.
Interruption event sequence:
- The server is streaming
response.audio.delta(loop). - The client sends
input_audio_buffer.append(the user starts speaking). - The server returns
response.done(status=cancelled), canceling the current response. - The server returns
input_audio_buffer.speech_started. - The client continues sending
input_audio_buffer.append; the server streamsconversation.item.input_audio_transcription.delta. - The server detects the end of speech and returns
input_audio_buffer.speech_stoppedandconversation.item.input_audio_transcription.completed. - The server commits the audio buffer internally, returning
input_audio_buffer.committedandconversation.item.created. - The server automatically starts a new round of inference and returns
response.created.
smart_turn mode
Combines acoustic perception with semantic understanding to detect the end of speech, filtering out backchannels, background noise, and other non-meaningful sounds. Non-semantic sounds are passed through via the conversation.item.ambient_audio_transcription.delta event and do not trigger a conversation turn.
To enable: Set turn_detection.type to smart_turn in the session.update event.
A complete conversation turn
Main differences from server_vad mode:
- Non-semantic sounds (such as "um" or "uh") do not trigger inference; instead, they are returned via the
ambient_audio_transcriptionevents. - Speech that was initially judged valid may later be retracted (
input_audio_buffer.speech_stoppedreturns withreason=turn_invalid), in which case inference is not triggered. - While waiting for the user's next input, the client can explicitly send
response.createto trigger inference.
| Phase | Direction | Event |
|---|---|---|
| Session initialization | Client -> Server | connect |
| Server -> Client | session.created | |
| Client -> Server | session.update | |
| Server -> Client | session.updated | |
| Voice input (loop) | Client -> Server | input_audio_buffer.append (sent continuously) |
| Invalid speech (0 to N times) | Server -> Client | conversation.item.ambient_audio_transcription.delta (streamed) |
| Server -> Client | conversation.item.ambient_audio_transcription.completed | |
| Valid speech input | Client -> Server | input_audio_buffer.append (sent continuously) |
| Server -> Client | input_audio_buffer.speech_started | |
| Client -> Server | input_audio_buffer.append (sent continuously) | |
| Server -> Client | conversation.item.input_audio_transcription.delta (streamed) | |
| Server -> Client | input_audio_buffer.speech_stopped | |
| Server -> Client | conversation.item.input_audio_transcription.completed | |
| Server (internal) | commit audio buffer | |
| Server -> Client | input_audio_buffer.committed | |
| Server -> Client | conversation.item.created | |
| Response generation | Server -> Client | response.created |
| Server -> Client | response.output_item.added | |
| Server -> Client | conversation.item.created | |
| Server -> Client | response.content_part.added | |
| Streaming output (loop) | Server -> Client | response.audio_transcript.delta (streamed) |
| Server -> Client | response.audio.delta (streamed) | |
| Output complete | Server -> Client | response.audio_transcript.done |
| Server -> Client | response.audio.done | |
| Server -> Client | response.content_part.done | |
| Server -> Client | response.output_item.done | |
| Server -> Client | response.done |
User interruption
Interruption handling is largely the same as in server_vad mode:
- The server is streaming
response.audio.delta(loop). - The client sends
input_audio_buffer.append(the user starts speaking). - The server returns
response.done(status=cancelled), canceling the current response. - The server returns
input_audio_buffer.speech_started. - The client continues sending
input_audio_buffer.append; the server streamsconversation.item.input_audio_transcription.delta. - The server returns
conversation.item.input_audio_transcription.completedandinput_audio_buffer.speech_stopped. - The server commits the audio buffer internally, returning
input_audio_buffer.committedandconversation.item.created. - The server automatically starts a new round of inference and returns
response.created.
Invalid turns
Speech that was initially judged valid may later be retracted (input_audio_buffer.speech_stopped returns with reason=turn_invalid), in which case inference is not triggered. The client should keep sending audio and wait for the next valid speech turn.
Invalid turn event sequence:
- The client continuously sends
input_audio_buffer.append. - The server returns
input_audio_buffer.speech_started. - The client continues sending
input_audio_buffer.append; the server streamsconversation.item.input_audio_transcription.delta. - The server returns
input_audio_buffer.speech_stopped(reason=turn_invalid). - The client continues sending audio, waiting for the next valid speech turn.
Voiceprint enrollment flow
In smart_turn mode, when voiceprint_audio_urls is included in the first session.update, the server asynchronously performs voiceprint enrollment (loading the target speaker's audio features) and notifies enrollment progress via events. A voiceprint enrollment failure does not block the normal conversation flow.
In chronological order, the voiceprint enrollment interaction flow is as follows:
- The client sends
session.update, including the voiceprint audio URL inturn_detection.voiceprint_audio_urls; the server returnssession.updated. - The server immediately starts voiceprint enrollment asynchronously, pushing a
voiceprint_audio_list.in_progressevent before returningsession.updated, carrying a uniqueitem_idfor this enrollment task. - The server returns
session.updated, confirming that the session configuration has taken effect. - After voiceprint enrollment completes, the server pushes a terminal event (with the same
item_idas in step 2):- On success:
voiceprint_audio_list.completed. - On failure:
voiceprint_audio_list.failed, with areasonfield explaining the failure (for example, the audio URL could not be downloaded).
- On success:
voiceprint_audio_urls only takes effect on the first session.update. Subsequent occurrences of this field are ignored.push-to-talk mode
The client manually controls audio submission and inference triggering. Suitable for push-to-talk scenarios.
To enable: Set turn_detection to null in the session.update event.
A complete conversation turn
In chronological order, the client and server interact as follows:
- The client continuously sends
input_audio_buffer.appendevents to append audio data. - After the user finishes speaking, the client sends
input_audio_buffer.committo commit the buffer. - The client sends
response.createto manually trigger inference. - The server generates a response, streaming text and audio.
| Phase | Direction | Event |
|---|---|---|
| Session initialization | Client -> Server | connect |
| Server -> Client | session.created | |
| Client -> Server | session.update | |
| Server -> Client | session.updated | |
| Voice input (loop) | Client -> Server | input_audio_buffer.append (sent continuously) |
| Server -> Client | conversation.item.input_audio_transcription.delta (streamed) | |
| Manual commit | Client -> Server | input_audio_buffer.commit (the user releases the push-to-talk key) |
| Server -> Client | conversation.item.input_audio_transcription.completed | |
| Server -> Client | input_audio_buffer.committed | |
| Server -> Client | conversation.item.created | |
| Manually trigger inference | Client -> Server | response.create (manually triggers inference) |
| Response generation | Server -> Client | response.created |
| Server -> Client | response.output_item.added | |
| Server -> Client | conversation.item.created | |
| Server -> Client | response.content_part.added | |
| Streaming output (loop) | Server -> Client | response.audio_transcript.delta (streamed) |
| Server -> Client | response.audio.delta (streamed) | |
| Output complete | Server -> Client | response.audio_transcript.done |
| Server -> Client | response.audio.done | |
| Server -> Client | response.content_part.done | |
| Server -> Client | response.output_item.done | |
| Server -> Client | response.done |
User interruption
The client sends response.cancel to cancel the current response; the server returns response.done (status cancelled, reason client_cancelled).
Interruption event sequence:
- The server is streaming
response.audio_transcript.deltaandresponse.audio.delta(loop). - The client sends
response.cancel. - The server returns
response.done(status=cancelled, reason=client_cancelled). - The client continues sending
input_audio_buffer.append; the server streamsconversation.item.input_audio_transcription.delta. - The client sends
input_audio_buffer.committo commit the buffer. - The server returns
conversation.item.input_audio_transcription.completed,input_audio_buffer.committed, andconversation.item.created. - The client sends
response.createto manually trigger a new round of inference. - The server returns
response.created, starting a new round of response.
Operation constraints by mode
| Operation | push-to-talk | server_vad | smart_turn |
|---|---|---|---|
| session.update | All fields can be changed when IDLE; some are restricted when not IDLE | All fields can be changed when IDLE; some are restricted when not IDLE | All fields can be changed when IDLE; some are restricted when not IDLE |
| input_audio_buffer.append | Allowed | Allowed | Allowed |
| input_audio_buffer.commit | Allowed | Ignored | Ignored |
| input_audio_buffer.clear | Allowed | Ignored | Ignored |
| response.create | Allowed (requires committing the buffer via input_audio_buffer.commit first; not allowed while a response is already being generated) | Allowed when no response is currently being generated; not allowed while a response is already being generated | Allowed while waiting for the user's next input; not allowed within an active turn (from input_audio_buffer.speech_started to response.done) |
| response.cancel | Allowed (during inference) | Allowed (during inference) | Allowed (during inference) |
| conversation.item.create/delete/retrieve | Allowed | Allowed | Allowed |
turn_detection and input_audio_format can only be changed before the first audio is sent (IDLE state).Error handling
| Type | Behavior | Example |
|---|---|---|
Client error (invalid_request_error) | Connection remains open; client is only notified | Invalid parameters, disallowed state, duplicate item_id |
Server error (server_error) | Connection is terminated | LLM connection failure, storage failure |