Skip to main content
WSS

Differences from /ws/v1/t2a_v2

This API targets streaming text input — piping an LLM’s streaming output straight into speech, token by token. The voice, audio and pronunciation parameters of task_start are identical to /ws/v1/t2a_v2, so an existing integration can reuse them as-is.

Event flow

  1. Establish the connection and receive connected_success
  2. Send task_start and receive task_started
  3. Send task_continue (at any granularity, including a single character); the server buffers the text and starts synthesizing
    • sentence_start is returned when a sentence starts synthesizing
    • audio arrives in chunks via task_continued
    • sentence_end is returned when that sentence is done
  4. Send task_cancel to interrupt; after task_canceled you may keep sending task_continue
  5. When a turn is over and you want its tail audio right away, send task_flush; the session continues after task_flushed
  6. Send task_finish; the server synthesizes any leftover buffered text, then returns task_finished and closes the connection
Do not conflate the three levels of completion: is_final marks the end of audio for one request, sentence_end marks the end of the current sentence, and task_finished marks the end of the whole session.
A connection can host only one synthesis session at a time. Sending task_start again after the task has started returns 2206 (illegal event order) and closes the connection.

Sentence buffering and latency

The server detects sentence boundaries from punctuation, so the punctuation in the text you send directly affects how natural the audio sounds:
The last row has a practical consequence for multi-turn conversations.If a turn ends with text that is both short and unpunctuated, it is not flushed by the short silence window and instead waits for a longer backstop window. Two ways to avoid that wait: end the last piece with sentence-final punctuation, or send task_flush to push it out explicitly.Note that task_finish is not a substitute — it closes the connection, so it cannot be used when running multiple turns over one connection.
If your application sanitizes an LLM’s output before forwarding it, keep the original punctuation. Without punctuation the server falls back to splitting purely by length, so pauses land in the wrong places and the audio sounds noticeably unnatural.
When the upstream source (for example an LLM) stalls, the audio will contain a matching gap — that is unavoidable. The server will not flush a half-finished sentence to fill the gap, because that would only make the listener hear half a word and then wait anyway.

Keeping the connection alive

A connection that stays idle for roughly 120 seconds is closed by the server with 2201. “Idle” means the server is neither receiving upstream events nor sending audio.
The server does not send WebSocket ping frames on its own. If your session has long silent periods (for example while waiting for the user to speak), send pings from the client — the server replies with pong and refreshes the activity timer. Keeping the TCP connection open is not enough to avoid 2201.

Send rate and retries

2205 means too much text is queued for synthesis on the server, usually because you are sending faster than synthesis can keep up.
2205 is not a quota rate limit, and it is a soft failure: neither the connection nor the session is closed. Just resend that task_continue a moment later — no reconnect and no second task_start are needed.
A single task_continue longer than 10,000 characters returns 2204; that piece is skipped and the connection and session likewise stay open.
Task Start Event
type:object

Sending the "task_start" event officially begins the speech synthesis task. The task is considered successfully started when the server returns a "task_started" event. Only after receiving this event can you send "task_continue" or "task_finish" events to the server.

Task Continue Event
type:object

After receiving the task_started event from the server, the task officially begins and you can send task_continue events carrying the text to synthesize.

Key difference from /ws/v1/t2a_v2: text is not synthesized one message at a time. It enters a server-side sentence buffer and is only sent for synthesis once it forms a sentence, so it is safe to send text character by character (or token by token):

  • flushed immediately on sentence-ending punctuation (。!?…;!?. and newline)
  • flushed on secondary punctuation (,、:,;:) once the buffered segment is long enough
  • force-split when the buffer reaches its length limit
  • after you stop sending for a short while, the leftover buffer is flushed automatically

Whitespace-only text is discarded silently and returns no error. If no new event is sent within 120s after the last server response, the WebSocket connection closes automatically.

Cancel Synthesis Event
type:object

Send task_cancel to interrupt synthesis immediately: the server discards any text still in the sentence buffer, aborts the in-flight synthesis, and replies with task_canceled.

Audio already delivered to the client is not revoked.

After cancelling, the session returns to the task_started state and you may keep sending task_continue without reconnecting. This is intended for barge-in during real-time conversation.

Flush pending text (without ending the session)
type:object

Send task_flush to make the server synthesize whatever text is still buffered, without ending the session or closing the connection. task_flushed is returned once that audio has been sent.

Use it when a turn is over but its last piece of text is short and unpunctuated. Such a remainder is not flushed by the short silence window (that would risk cutting mid-word), so it otherwise waits for a longer backstop window. task_flush gets that audio out immediately.

Difference from task_finish: task_finish closes the connection, so it cannot be used to flush one turn's tail when you run multiple turns over a single connection. After task_flush the session stays in task_started and you may keep sending task_continue.

If the buffer happens to be empty, task_flushed is still returned normally; that is not an error.

Task Finish Event
type:object

On receiving task_finish, the server first flushes any text still sitting in the sentence buffer, waits until all of that audio has been returned, and only then replies with task_finished and closes the connection.

As a result a trailing incomplete sentence is never dropped, and the client does not need to append punctuation before finishing.

Connected Success Event
type:object

Notification that T2A task has started

Task Started Event
type:object

Notification that T2A task has started

Sentence Start Event
type:object

Returned when the server has buffered a complete sentence and starts synthesizing it. The audio for that sentence then arrives in chunks via task_continued until sentence_end.

Use it to count how many sentences the server actually grouped the text into

Task Continued Event
type:object

Notification that T2A task is continuing

Sentence End Event
type:object

Returned when all audio for the current sentence has been delivered.

Note the three levels of completion: is_final marks the end of audio for one request, sentence_end marks the end of the current sentence, and task_finished marks the end of the whole session

Cancelled Event
type:object

The server returns task_canceled to confirm the interruption took effect. You may continue sending task_continue afterwards

Pending text flushed
type:object

The server returns task_flushed to indicate that all audio for this task_flush has been sent. It is ordered after the audio frames produced by the flush, so receiving it means this turn's audio is complete. You may keep sending task_continue afterwards.

Task Finished Event
type:object

Notification that T2A task has completed successfully

Task Failed Event
type:object

If the task_failed event is received, it indicates that the task has failed. In this case, the WebSocket connection must be closed, and the error should be handled.