Docs
Quickstart
Everything you need for a first transcript. The API reference covers every parameter, message and error.
| What | Endpoint |
|---|---|
| Streaming | wss://api.saidwire.com/v1/listen (WebSocket) |
| Files | POST https://api.saidwire.com/v1/listen |
| OpenAI-compatible | POST https://api.saidwire.com/v1/audio/transcriptions (base URL https://api.saidwire.com/v1) |
| Status | GET https://api.saidwire.com/health |
| Auth | Authorization: Token <API key> or Bearer <API key> |
Get a key in the dashboard: 120 free hours, no card. The API is always on.
1. Stream live audio
Open a WebSocket with your key, send binary audio frames of 20 to 100 ms in real time, and read JSON messages back. Send CloseStream when you are done.
- interim_results=true for live guesses while the person speaks.
- Finalize asks for a final right now, when your own detector says the user stopped. Final transcript 35 ms median (p95 46 ms) after Finalize, measured in US East; add your network round trip.
- endpointing sets the pause, in ms (minimum 500), that ends a turn on its own.
# pip install websockets (Python 3.10+)
import asyncio, json, os, 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=500")
async def main(path):
with wave.open(path) as w: # 16 kHz, mono, 16-bit
pcm = w.readframes(w.getnframes())
headers = {"Authorization": f"Token {os.environ['SAIDWIRE_API_KEY']}"}
async with connect(URL, additional_headers=headers) as ws:
async def reader():
async for raw in ws:
m = json.loads(raw)
if m["type"] == "Results" and m["is_final"]:
print(m["channel"]["alternatives"][0]["transcript"])
r = asyncio.create_task(reader())
for i in range(0, len(pcm), 640): # 20 ms frames, real time
await ws.send(pcm[i:i + 640])
await asyncio.sleep(0.02)
await ws.send(json.dumps({"type": "CloseStream"}))
await r
asyncio.run(main("call.wav"))// npm install ws
const WebSocket = require("ws");
const ws = new WebSocket(
"wss://api.saidwire.com/v1/listen?encoding=linear16&sample_rate=16000&interim_results=true&punctuate=true",
{ headers: { Authorization: `Token ${process.env.SAIDWIRE_API_KEY}` } });
ws.on("message", (raw) => {
const m = JSON.parse(raw);
if (m.type === "Results")
console.log(m.is_final ? "final " : "interim", m.channel.alternatives[0].transcript);
});
ws.on("open", () => {
// send binary 16-bit PCM frames (20-100 ms each) as they are captured, then:
// ws.send(JSON.stringify({ type: "CloseStream" }));
});2. Transcribe a file
POST the file to /v1/listen, or use the OpenAI-compatible endpoint with the official SDKs. WAV, MP3, FLAC, Ogg, WebM and M4A are accepted, up to 60 minutes.
# Transcribe a recorded file (WAV, MP3, FLAC, Ogg, WebM or M4A, up to 60 min)
curl -s -X POST "https://api.saidwire.com/v1/listen?punctuate=true" \
-H "Authorization: Token $SAIDWIRE_API_KEY" \
-H "Content-Type: audio/wav" \
--data-binary @meeting.wav \
| jq -r '.results.channels[0].alternatives[0].transcript'# pip install openai
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.saidwire.com/v1", api_key=os.environ["SAIDWIRE_API_KEY"])
with open("meeting.mp3", "rb") as f:
r = client.audio.transcriptions.create(model="saidwire-en", file=f)
print(r.text)curl https://api.saidwire.com/v1/audio/transcriptions \
-H "Authorization: Bearer $SAIDWIRE_API_KEY" \
-F file=@meeting.mp3 -F model=saidwire-en3. Switch an existing integration
Saidwire is compatible with Deepgram's API and with OpenAI's transcription API. If your app or framework lets you set the base URL, change it and the key.
See the compatibility notes and the integration guides.
# Already using a Deepgram-compatible client? Change two values.
- base URL wss://<your current endpoint>/v1/listen
+ base URL wss://api.saidwire.com/v1/listen
- API key <your current key>
+ API key sk_live_...
# Query parameters, Results messages, KeepAlive, Finalize and
# CloseStream keep the same names. Differences are listed in the docs.