Saidwire Speech-to-Text API · Early access
Live speech-to-text, built for speed.
Stream audio in, get each word back the moment it's committed, then a punctuated final transcript and an end-of-turn signal. Built for voice agents, live captions and anything that has to react while the speaker is still talking.
What you get
Instant words
Turn on early_words=true and every word arrives as its own EarlyWord message the moment the recogniser commits it, well before the final transcript for that sentence. Start planning a reply, catch "stop" or "wait" for barge-in, or fire a tool on a keyword.
Corrected finals
Interim results while someone speaks, then a final Results message with case, punctuation and word timings. Consecutive finals tile the stream with no gaps or repeats.
End of turn
speech_final after a pause you choose (default 300 ms), plus optional UtteranceEnd and SpeechStarted events, so your agent knows when to answer and when it's being interrupted.
Drop-in protocol
The API speaks the most widely used streaming speech-to-text WebSocket protocol. If your app or agent framework already uses a streaming STT client with a configurable base URL, switch by changing the URL and the key. Nothing else.
Phone and web audio
Linear PCM at 8 to 48 kHz, μ-law and A-law telephone audio, or a WAV stream. English (US, UK and other English accents). One channel per stream.
Your audio stays yours
Audio is processed in memory and never written to disk. Transcripts aren't logged. We don't train on customer audio. Every stream gets a request_id for support.
Quickstart
Open a WebSocket to /v1/listen with your key, send raw audio as binary frames, read JSON messages back.
# pip install websockets (Python 3.10+) # Streams a 16 kHz mono 16-bit WAV in real time and prints words as they arrive. import asyncio, json, wave from websockets.asyncio.client import connect URL = ("wss://api.saidwire.com/v1/listen" "?encoding=linear16&sample_rate=16000&interim_results=true" "&punctuate=true&endpointing=300&early_words=true") KEY = "sk_live_..." async def main(path): w = wave.open(path) frame = w.getframerate() // 50 # 20 ms of audio async with connect(URL, additional_headers={"Authorization": f"Token {KEY}"}) as ws: async def send(): while chunk := w.readframes(frame): await ws.send(chunk) await asyncio.sleep(0.02) # real time, like a live mic await ws.send(json.dumps({"type": "CloseStream"})) sender = asyncio.create_task(send()) async for raw in ws: m = json.loads(raw) if m["type"] == "EarlyWord": print("word ", m["punctuated_word"]) elif m["type"] == "Results" and m["is_final"]: print("final ", m["channel"]["alternatives"][0]["transcript"], "(end of turn)" if m["speech_final"] else "") await sender asyncio.run(main("hello.wav"))
// Browsers can't set headers on a WebSocket: pass the key as a subprotocol. // Use a short-lived key in browsers, never your server key. // Send 16-bit PCM (e.g. from an AudioWorklet); compressed browser formats are not supported yet. const url = "wss://api.saidwire.com/v1/listen?encoding=linear16&sample_rate=16000&interim_results=true&early_words=true"; const ws = new WebSocket(url, ["token", KEY]); ws.binaryType = "arraybuffer"; ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.type === "EarlyWord") showWord(m.punctuated_word); if (m.type === "Results" && m.is_final) showFinal(m.channel.alternatives[0].transcript, m.speech_final); }; // pcm16 = Int16Array of 20-100 ms of mono audio function onAudio(pcm16) { if (ws.readyState === 1) ws.send(pcm16.buffer); } // when done: ws.send(JSON.stringify({ type: "CloseStream" }));
# Stream a raw 8 kHz μ-law phone recording with websocat (https://github.com/vi/websocat). # --binary sends stdin as binary frames; replies print one JSON message per line. websocat --binary -H="Authorization: Token sk_live_..." \ "wss://api.saidwire.com/v1/listen?encoding=mulaw&sample_rate=8000&early_words=true" \ < call.ulaw
Full message reference, parameters, limits and error codes: API docs.
Pricing
Free trial
$25 of credit
- About 83 hours of audio, no card to start
- Every feature, including instant words
- 2 streams at once
Pay as you go
$0.30 per audio hour
- Billed per second of audio you send, not per minute rounded up
- Billing starts only after your free credit is used
- Instant words included, no add-on fee
- 4 streams at once, monthly spend cap you set
Growth
Lower rate with a monthly commit
- Lower rate for a monthly commitment
- Higher stream limits
- Email support with a named engineer
Enterprise
Custom
- Reserved capacity
- Uptime terms in writing
- Security review and your paper
Status
Our internal measurement, using Coval's open-source benchmark method over the public internet: the final transcript arrives about 45 ms after the speaker stops (median, when your app sends Finalize at end of speech), with a 3.7% word error rate on a 117-clip sample of Coval's benchmark mix. That puts us among the top three shared speech APIs on Coval's public leaderboard for time to final transcript. We're preparing our submission for independent testing.
- Not yet supported: multichannel, speaker labels, languages other than English, keyword boosting.
- Planned: numeral and currency formatting.
Get an API key
Tell us what you're building. We'll reply with a key and trial credit, usually within one business day. One reply from a person, no sequence.
Questions developers ask
How fast is it?
We publish our method, datasets and results on the benchmarks page, measured from the client side so network time is included. Results on your audio will differ; the trial credit is there so you can measure it yourself.
How is usage counted?
Seconds of audio you send, from the first byte to the end of the stream, silence included. Not the time a connection sits open after you stop sending, and not rounded up to the minute.
Do I have to change my code?
If your client already speaks the common streaming STT WebSocket protocol, no: change the base URL and the key. Our one addition, EarlyWord, is opt-in and ignored by clients that don't ask for it.
Can I benchmark you and publish the results?
Yes. Benchmarking and publishing results is allowed under our terms. Tell us which datasets you used and we'll link your results.
What happens to my audio?
It's processed in memory and discarded. We keep usage records (key, time, seconds of audio) for billing and short-lived technical logs without transcript text. Details in the API privacy notice.