Quickstart
You will transcribe a WAV file as if it were spoken live: the same code transcribes a microphone or a phone call.
Start with your coding agent
Section titled “Start with your coding agent”Building with an AI coding agent (Claude Code, Cursor, Copilot…)? Paste this prompt, then describe what you build. It gives the agent the documentation and the rules that avoid the usual integration bugs.
You are integrating the Gladia Enterprise real-time speech-to-text API.
Documentation (read it before writing code, every page also exists in Markdown):- Everything in one file: https://eu1.docs.gladia.io/llms-full.txt- Index of pages: https://eu1.docs.gladia.io/llms.txt- OpenAPI 3.1 contract, WebSocket messages under x-websocket: https://eu1.docs.gladia.io/openapi.json
How the API works:- Create a session with POST {API_URL}/v2/live, header x-gladia-key: <API key>. The body describes the audio (encoding, sample_rate, bit_depth, channels), the model and the options. The answer has an id and a WebSocket url.- Stream the audio to that url (binary frames of raw samples, about 100 ms each), read the JSON messages, send {"type": "stop_recording"} when done. The server sends the last results, then closes with code 1000.- API_URL is the account's region: https://eu1.api.gladia.io (Europe) or https://us1.api.gladia.io (United States).- Models: solaria-3 (multilingual, translation), solaria-1 (99 languages), trantoria-1 (lowest latency, set the language). Check the docs' features-by-model table before combining a model and a feature.
Rules:1. Use the official SDK: Python gladiaio-sdk, JavaScript @gladiaio/sdk, with api_url / apiUrl set to API_URL. It buffers the audio until acknowledged and reconnects without losing words. Do not hand-write the WebSocket client unless the SDK cannot do the job.2. Python SDK: LiveV2InitRequest silently drops the Gladia Enterprise options (numerals, pii, end_of_turn, diarization, punctuation, profile, turn_router, named_entity_recognition with options). For those, create the session with an HTTP POST, then call client.live_v2().connect_session(LiveV2ConnectSessionOptions(id, url)). The Python SDK reports pii and end_of_turn messages as errors: read them with the JavaScript SDK or a raw WebSocket. The JavaScript SDK sends any option and delivers every message.3. Never ship the API key to a browser or a mobile app: create the session on the server, give the client only the session url (single use, valid 60 seconds).4. The audio format in the init body must match the audio exactly; send raw samples, no WAV header, channels interleaved, little-endian.5. Partial transcripts replace each other: key them by data.id and keep only the final (is_final: true).6. Keep the API key in an environment variable (GLADIA_API_KEY), never in code.7. Handle failures: POST /v2/live errors have a JSON body with message and validation_errors; a WebSocket closed with 1011 carries the reason (rejected: ... means an option the model refused); 429 means too many open sessions; 503 means retry with a backoff; 500 "no inference endpoint available" means no model in the region serves that combination.8. Each feature page of the docs has a "Limits and gotchas" section: read the one of every feature you use.9. Test with a real 16-bit WAV file end to end before wiring a microphone or a phone line.Or follow the steps yourself:
1. Get an API key
Section titled “1. Get an API key”Sign in to Gladia Workspace, open API keys and create a key. A key restricted to some products needs the Real-time STT scope. Keep it on your server: anyone with the key can use your account.
export GLADIA_API_KEY="ge_..."2. Install the SDK
Section titled “2. Install the SDK”pip install gladiaio-sdk # Pythonnpm install @gladiaio/sdk # JavaScript and TypeScript3. Transcribe a file
Section titled “3. Transcribe a file”Save the program, then run it on a 16-bit PCM WAV file: python transcribe.py meeting.wav or
node transcribe.mjs meeting.wav. It prints each sentence once it is final.
# pip install gladiaio-sdkimport osimport sysimport threadingimport wave
from gladiaio_sdk import GladiaClient, LiveV2InitRequest
API_URL = os.environ.get("GLADIA_API_URL", "https://eu1.api.gladia.io")API_KEY = os.environ["GLADIA_API_KEY"]
with wave.open(sys.argv[1]) as wav: # a 16-bit PCM WAV file rate, channels = wav.getframerate(), wav.getnchannels() audio = wav.readframes(wav.getnframes())
config = { "encoding": "wav/pcm", "sample_rate": rate, "bit_depth": 16, "channels": channels, "model": "solaria-3", "language_config": { "languages": [ "en" ] }}
client = GladiaClient(api_key=API_KEY, api_url=API_URL)session = client.live_v2().start_session(LiveV2InitRequest.from_dict(config))ended, errors = threading.Event(), []
@session.on("message")def on_message(message): if message.type == "transcript" and message.data.is_final: print(message.data.utterance.text)
session.on("error", errors.append)session.once("ended", lambda _: ended.set())
step = rate * channels * 2 // 10 # 100 ms of audio per chunkfor start in range(0, len(audio), step): session.send_audio(audio[start : start + step]) # live audio: send each chunk as it is capturedsession.stop_recording()
ended.wait(timeout=60)sys.exit(1 if errors or not ended.is_set() else 0)// npm install @gladiaio/sdkimport { readFileSync } from "node:fs";import { GladiaClient } from "@gladiaio/sdk";
const { sampleRate, channels, pcm } = readWav(process.argv[2]); // a 16-bit PCM WAV file
const config = { encoding: "wav/pcm", sample_rate: sampleRate, bit_depth: 16, channels, model: "solaria-3", language_config: { languages: [ "en" ] }};
const client = new GladiaClient({ apiKey: process.env.GLADIA_API_KEY, apiUrl: process.env.GLADIA_API_URL ?? "https://eu1.api.gladia.io",});const session = client.liveV2().startSession(config);
session.on("message", (message) => { if (message.type === "transcript" && message.data.is_final) console.log(message.data.utterance.text);});session.on("error", (error) => { console.error(error); process.exitCode = 1;});session.once("ended", () => process.exit());
const step = (sampleRate * channels * 2) / 10; // 100 ms of audio per chunkfor (let start = 0; start < pcm.length; start += step) { session.sendAudio(pcm.subarray(start, start + step)); // live audio: send each chunk as it is captured}session.stopRecording();
function readWav(path) { const file = readFileSync(path); let fmt, pcm; for (let pos = 12; pos < file.length; ) { const id = file.toString("ascii", pos, pos + 4); const size = file.readUInt32LE(pos + 4); if (id === "fmt ") fmt = { channels: file.readUInt16LE(pos + 10), sampleRate: file.readUInt32LE(pos + 12) }; if (id === "data") pcm = file.subarray(pos + 8, pos + 8 + size); pos += 8 + size + (size % 2); } return { ...fmt, pcm };}The same session with a raw WebSocket. You then handle acknowledgments and reconnections yourself (Reconnections).
# pip install requests websocketsimport asyncioimport jsonimport osimport sysimport wave
import requestsimport websockets
API_URL = os.environ.get("GLADIA_API_URL", "https://eu1.api.gladia.io")
async def main(path: str) -> None: with wave.open(path) as wav: # a 16-bit PCM WAV file rate, channels = wav.getframerate(), wav.getnchannels() audio = wav.readframes(wav.getnframes()) created = requests.post( f"{API_URL}/v2/live", headers={"x-gladia-key": os.environ["GLADIA_API_KEY"]}, json={"encoding": "wav/pcm", "sample_rate": rate, "bit_depth": 16, "channels": channels}, timeout=10, ) created.raise_for_status()
async with websockets.connect(created.json()["url"]) as ws:
async def send() -> None: step = rate * channels * 2 // 10 # 100 ms of audio per chunk for start in range(0, len(audio), step): await ws.send(audio[start : start + step]) # live audio: send each chunk as it is captured await ws.send(json.dumps({"type": "stop_recording"}))
sender = asyncio.create_task(send()) async for raw in ws: # the server closes the connection once everything is sent message = json.loads(raw) if message["type"] == "transcript" and message["data"]["is_final"]: print(message["data"]["utterance"]["text"]) await sender
asyncio.run(main(sys.argv[1]))Hello, thanks for calling. How can I help you?I'd like to change my delivery address.What happened
Section titled “What happened”-
The program created a session with
POST /v2/live: its audio format, model and options. The answer has the sessionidand a WebSocketurl, valid 60 seconds and for this session only:Terminal window curl -X POST https://eu1.api.gladia.io/v2/live \-H "x-gladia-key: $GLADIA_API_KEY" \-H "content-type: application/json" \-d '{"encoding": "wav/pcm", "sample_rate": 16000, "bit_depth": 16, "channels": 1, "model": "solaria-3"}'{"id": "0199d7a2-5c3e-7b41-9f0a-3c2d1e4f5a6b","created_at": "2026-10-12T09:04:17.210Z","url": "wss://eu1.api.gladia.io/v2/live?token=eyJhbGciOi..."} -
It streamed the audio to that URL in 100 ms chunks.
-
It printed the final transcripts as they came, then stopped the recording: the API sent the last ones and closed the connection.
The full result stays available with GET /v2/live/{id}.
Common mistakes
Section titled “Common mistakes”- The audio format does not match the configuration.
sample_rate,bit_depthandchannelsmust describe what you send: wrong values give gibberish or nothing, never an error. The programs above read them from the file. - A WAV header in a raw stream. Send raw samples, without the 44-byte header, when you stream from a microphone or a phone line.
- The API key in a browser or a mobile app. Create the session on your server and give the client only its
url(Authentication). - The URL used too late. It expires 60 seconds after
POST /v2/live: create the session when the audio is about to start. - Wrong region. Your key works on your account’s region only (Regions): a key of
eu1gets a401onus1.
- Models: choose speed or accuracy.
- How a session works: the messages and their order.
- Audio intelligence: translation, entities, PII redaction, sentiment.