# 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

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.

```text title="Prompt for your coding agent"
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

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.

```bash
export GLADIA_API_KEY="ge_..."
```

## 2. Install the SDK

> **Use the SDK.** The Gladia SDKs stream the audio, keep it until the API has transcribed it, and reconnect after a network drop
without losing a word. Most integration issues come from hand-written WebSocket clients.

```bash
pip install gladiaio-sdk      # Python
npm install @gladiaio/sdk     # JavaScript and TypeScript
```

## 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.

**Python SDK**

```python title="transcribe.py"
# pip install gladiaio-sdk
import os
import sys
import threading
import 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 chunk
for start in range(0, len(audio), step):
    session.send_audio(audio[start : start + step])  # live audio: send each chunk as it is captured
session.stop_recording()

ended.wait(timeout=60)
sys.exit(1 if errors or not ended.is_set() else 0)
```

**JavaScript SDK**

```js title="transcribe.mjs"
// npm install @gladiaio/sdk
import { 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 chunk
for (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 };
}
```

**Python, no SDK**

The same session with a raw WebSocket. You then handle acknowledgments and reconnections yourself
([Reconnections](/live/reconnections/)).

```python title="transcribe_raw.py"
# pip install requests websockets
import asyncio
import json
import os
import sys
import wave

import requests
import 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

1. The program **created a session** with `POST /v2/live`: its audio format, model and options. The answer has the
   session `id` and a WebSocket `url`, valid 60 seconds and for this session only:

   ```bash
   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"}'
   ```

   ```json
   {
     "id": "0199d7a2-5c3e-7b41-9f0a-3c2d1e4f5a6b",
     "created_at": "2026-10-12T09:04:17.210Z",
     "url": "wss://eu1.api.gladia.io/v2/live?token=eyJhbGciOi..."
   }
   ```

2. It **streamed the audio** to that URL in 100 ms chunks.
3. 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}`](/api-reference/v2/live/get/).

## Common mistakes

- **The audio format does not match the configuration.** `sample_rate`, `bit_depth` and `channels` must 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](/introduction/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](/introduction/regions/)): a key of
  `eu1` gets a `401` on `us1`.

## Next

- [Models](/introduction/models/): choose speed or accuracy.
- [How a session works](/live/how-it-works/): the messages and their order.
- [Audio intelligence](/features/translation/): translation, entities, PII redaction, sentiment.
