Reference WebSocket protocol

WebSocket protocol

Munsit runs two WebSockets: one that streams text in and returns audio chunks, and one that streams audio in and returns live transcripts. This page is the full wire protocol for both — connection, auth, message shapes and lifecycle.

1

The two sockets

Same host, same /api/v1 prefix, opposite directions.

SocketPathYou sendYou receive
WSS Text to speech/websocket/text-to-speechJSON messages carrying text chunksBase64-encoded PCM audio chunks
WSS Speech to text (legacy)/websocket/speech-to-textAudio chunks (WAV, then WAV or raw PCM)Cumulative Arabic transcript strings
When to use the TTS socket. It shines when input text is streamed or generated in chunks and you need low-latency, real-time audio. If the entire text is available upfront, partial generation adds buffering — a standard HTTP request can be lower latency and is much simpler for quick prototyping.
2

Text to speech — audio out

Streaming synthesisWSS/websocket/text-to-speech
wss://api.munsit.com/api/v1/websocket/text-to-speech?x-api-key=YOUR_API_KEY

Authentication. API key via the x-api-key query parameter, or in the initial connection message as x_api_key. After the socket opens you must send an initConnection message before any text.

json · initConnection
{ "type": "initConnection", "model_id": "faseeh-v1-preview", "voice_id": "ar-najdi-male-2", "voice_settings": { "stability": 0.5, "similarity_boost": 0.75, "speed": 1.0 }, "output_format": "pcm_24000", "x_api_key": "YOUR_API_KEY"}
Response
{ "type": "connectionInitialized" }

initConnection fields.

FieldTypeRequiredDescription
typestringYesMust be "initConnection".
model_idstringNoModel ID to use (default: "faseeh-v1-preview").
voice_idstringYesThe voice ID to use for synthesis.
voice_settingsobjectNoVoice configuration.
voice_settings.stabilitynumberNoStability setting (default: 0.5).
voice_settings.similarity_boostnumberNoSimilarity boost (default: 0.75).
voice_settings.speednumberNoSpeed setting, range 0.7–1.2 (default: 1.0).
output_formatstringNoAudio output format: "pcm_8000", "pcm_16000", "pcm_22050", "pcm_24000" (default: "pcm_24000"). This socket tops out at 24 kHz — for 48 kHz engine-native audio use the HTTP endpoints (synthesize, streaming output, voice preview) with sample_rate=48000.
x_api_keystringNoAPI key (if not provided in query parameter).

text fields and the audio response.

FieldTypeRequiredDescription
typestringYesMust be "text".
textstringYesText to convert to speech.
flushbooleanNoForce generation of audio even if buffer is small (default: false).
try_trigger_generationbooleanNoAttempt to trigger generation immediately (default: false).
Response fieldTypeDescription
audiostringBase64-encoded PCM audio data.
sampleRatenumberSample rate of the audio (typically 24000 Hz).
3

Speech to text — audio in

The speech-to-text socket below is deprecated. WS /websocket/speech-to-text remains available for existing integrations but receives no new recognition features — no word timestamps, turn events, hotwords, confidence, sentiment or gender. New integrations should use WS /api/v1/listen. Finalization (end_of_stream) and min_buffer_seconds were added here as correctness fixes, not as new capability. It is frozen, not scheduled for removal, and stays available for existing integrations; any change to that would be announced on the Changelog.
Streaming transcriptionWSS/websocket/speech-to-text
wss://api.munsit.com/api/v1/websocket/speech-to-text?x-api-key=YOUR_MUNSIT_API_KEY&model=munsit

Authentication. The server accepts any one of three methods; at least one is required. If auth is invalid, the connection is rejected or closed — there is no dedicated authentication_error event.

FieldTypeRequiredDescription
x-api-keystringNoAPI key in header or query.
AuthorizationstringNoBearer token header.
tokenstringNoToken query param fallback for browsers.
Query parameterTypeRequiredDescription
modelstringNoASR model to use: munsit (default) or munsit-en-ar (mixed Arabic-English with code-switching).
min_buffer_secondsnumberNoSeconds of audio that must accumulate before an interim transcription is emitted. Default 0.5, clamped to 0.15.0. Lower it for faster partials on short answers. It does not gate the final result — the pass triggered by end_of_stream runs at any duration.

Audio input. The first chunk must be WAV (with headers); subsequent chunks can be WAV or raw PCM. audioBuffer must be an array of byte values (0–255). Any chunk size works — 100–500 ms is typical for live audio, and smaller chunks lower latency without changing what is recognized. Two client message formats are accepted:

json · primary
{ "event": "audio_chunk", "data": { "audioBuffer": [1, 2, 3] }}

Server events.

EventDirectionTypeMeaning
audio_chunkclient → serverArray<Uint8>Audio bytes; first chunk should include full WAV headers, PCM accepted after.
end_of_streamclient → serverSignals end of audio. Transcribes whatever is still buffered, at any duration, and replies with a final transcription then finalized. Send this before closing.
transcriptionserver → clientstringCumulative Arabic transcript generated from all received chunks. Carries an isFinal boolean.
finalizedserver → clientstringThe complete transcript for the session. Emitted once, in response to end_of_stream. Safe to close the socket after this.
transcription_errorserver → clientstringError details during streaming transcription.

Finalizing a stream. Closing the socket does not flush buffered audio, and waiting after the audio stops does not produce a final result — an interim hypothesis stays isFinal: false indefinitely, and audio shorter than min_buffer_seconds produces no event at all. Send end_of_stream, wait for finalized, then close.

json · client
{ "event": "end_of_stream" }
Single-word answers — «نعم», «لا», a city name — are typically under min_buffer_seconds, so end_of_stream is the only thing that will return them. Clients that open one socket per utterance must send it every time. On WS /api/v1/listen the equivalent is the CloseStream control frame, and the flag is is_final.

Recommended flow. Connect with auth → confirm the socket is open on the client side → emit audio_chunk payloads as audio arrives → listen for transcription_error and handle failures → listen for transcription and render live text updates → send end_of_stream when the speaker stops → wait for finalized → close the socket.

4

Errors

On the TTS socket, errors arrive as a typed JSON message. On the STT socket, listen for the transcription_error event; invalid auth is handled by rejecting or closing the connection.

Error messagetext-to-speech socket
{
  "type": "error",
  "errorCode": 40101,
  "errorMessage": "Invalid API key"
}
FieldTypeDescription
typestringAlways "error".
errorCodenumberNumeric error code (e.g. 40101, 40001).
errorMessagestringHuman-readable error message.
5

Full lifecycle example

Open, initialize, stream text, collect audio, handle errors — the complete TTS round-trip in the browser or Node.

javascript
const ws = new WebSocket('wss://api.munsit.com/api/v1/websocket/text-to-speech?x-api-key=YOUR_API_KEY');ws.onopen = () => { // Initialize connection ws.send(JSON.stringify({ type: "initConnection", model_id: "faseeh-v1-preview", voice_id: "ar-najdi-male-2", voice_settings: { stability: 0.5, similarity_boost: 0.75, speed: 1.0 }, output_format: "pcm_24000" }));};ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === "connectionInitialized") { // Connection ready, send text ws.send(JSON.stringify({ type: "text", text: "مرحبا بك في فصيح " })); } else if (data.audio) { // Process audio chunk const audioData = atob(data.audio); // Handle audio playback } else if (data.type === "error" || data.errorCode) { console.error("Error:", data.errorMessage); }};ws.onerror = (error) => { console.error("WebSocket error:", error);};ws.onclose = () => { console.log("WebSocket closed");};
6

Best practices

Five habits that keep streams smooth.

PracticeWhy
Always initializeSend initConnection immediately after opening the TTS connection.
Handle errorsCheck for error messages in responses.
Flush when doneUse flush: true when sending the last text chunk to ensure all audio is generated.
Close gracefullySend closeConnection before closing the WebSocket.
Buffer audioCollect audio chunks and play them sequentially for smooth playback.

Working with an AI assistant? Every page is available as Markdown: add .md to the URL, or send an Accept: text/markdown header. For the whole documentation in one request, point it at llms-full.txt; the page index is llms.txt. Or use Copy Page, top right.