Docs / Platform

Streaming

One WebSocket, wss://api.waridi.io/v1/stream, handles real-time speech recognition, real-time speech generation, or both at once. Use it for voice agents, live captions and anything where people are waiting on the other end.

Latency goal. For voice agents, our target is first reply audio in about 500 ms after the caller stops speaking, and always under 800 ms. This is a target for the preview, not a measured result or a guarantee.

Connecting

Open the socket with your API key in the Authorization header, then send a session.start message. Choose stt, tts or duplex as the mode.

import asyncio
from waridi import AsyncWaridi

client = AsyncWaridi()

async def main():
    async with client.stream.connect(
        mode="stt",
        model="sikia-1",
        language="sw-TZ",
        encoding="pcm_s16le",
        sample_rate=16000,
    ) as stream:
        asyncio.create_task(stream.send_file("simu.wav"))
        async for event in stream:
            if event.type == "transcript.final":
                print(event.text)

asyncio.run(main())
import { Waridi } from "@waridi/sdk";

const client = new Waridi();

const stream = await client.stream.connect({
  mode: "stt",
  model: "sikia-1",
  language: "sw-TZ",
  encoding: "pcm_s16le",
  sampleRate: 16000,
});

stream.on("transcript.partial", (e) => process.stdout.write("\r" + e.text));
stream.on("transcript.final", (e) => console.log("\n" + e.text));

microphone.on("data", (chunk: Buffer) => stream.sendAudio(chunk));
# cURL cannot hold a WebSocket open. To try the raw protocol, use wscat:
npm install -g wscat
wscat -c "wss://api.waridi.io/v1/stream" \
  -H "Authorization: Bearer $WARIDI_API_KEY"
# then paste:
{"type": "session.start", "mode": "tts", "model": "sauti-standard", "voice": "zawadi", "format": "opus"}
{"type": "text.append", "text": "Karibu tena!"}
{"type": "text.flush"}

Session options

Field Modes Description
mode all stt, tts or duplex
model all sikia-1 for stt. sauti-standard or sauti-pro for tts. In duplex, pass stt_model and tts_model
language all sw-TZ (default), sw-KE or auto for stt
encoding stt Input audio: pcm_s16le, opus or mulaw
sample_rate all 8000 for mulaw. 16000 or 24000 recommended otherwise
voice tts Voice ID
format tts Output audio: pcm_s16le, opus, mp3 or mulaw
vad stt Default true. Sends speech.started and speech.ended events
interim_results stt Default true. Sends transcript.partial events

Client messages

Audio for recognition is sent as binary frames. Everything else is a JSON text frame.

Type Description
session.start First message. Carries the session options above
(binary frame) Raw audio in the declared encoding, 20–100 ms per frame
text.append Text to speak. Can be sent token by token from your LLM
text.flush Speak everything appended so far, even mid-sentence
response.cancel Stop speaking now, for example when the caller interrupts
session.end Finish cleanly. The server sends remaining events, then closes

Server events

Type Description
session.started Session accepted. Includes session_id and the resolved options
speech.started Voice activity detected on the input
transcript.partial Interim text that may still change
transcript.final Stable text for a finished utterance, with start_ms, end_ms and language
speech.ended The speaker paused long enough to count as end of turn
audio.chunk Generated speech. Sent as a binary frame, preceded by this JSON header with seq and duration_ms
audio.done All audio for the last flush has been sent
error Something went wrong. See Errors
session.ended Usage summary, then the server closes the socket

Example events:

{"type": "session.started", "session_id": "ses_01J9Z8A0TT", "mode": "stt", "model": "sikia-1"}
{"type": "speech.started", "at_ms": 140}
{"type": "transcript.partial", "text": "nataka kulipa"}
{"type": "transcript.final", "text": "Nataka kulipa bili ya maji.", "language": "sw", "start_ms": 140, "end_ms": 1980}
{"type": "speech.ended", "at_ms": 2400}

Interruptions

In duplex mode, if speech.started arrives while you are playing audio, the caller is talking over the agent. Send response.cancel, stop local playback, and wait for the next transcript.final. Waridi Agents handle this for you.

Limits and close codes

  • Idle sessions close after 30 seconds without audio or text.
  • One session can last up to 60 minutes. Open a new one to continue.
  • Concurrent sessions are limited per plan. See Rate limits.
Close code Meaning
1000 Normal close after session.end
4001 Authentication failed
4008 Idle timeout
4029 Concurrent session limit reached
4400 Invalid session.start or malformed message
1011 Server error. Safe to reconnect with backoff