SDKs

Official client SDKs are available for Python and TypeScript/Node. Both cover the full API: instant and demand streaming over the /audio/v1/listen WebSocket, whole-file transcription over POST /audio/v1/transcribe, async transcription jobs over POST /audio/v1/transcriptions, PII redaction, keyword boosting, word timestamps, and transcript assembly helpers. Source, full guides, and runnable examples live in the bw_labs_sdks repository. The TypeScript SDK is available from npm, and the Python SDK is available from PyPI.

Create an API key from your dashboard and set it as BW_STT_API_KEY in your environment; both SDKs pick it up automatically.

Install

Once version 0.2.0 is on PyPI, install the Python SDK with:

pip install bw-stt

The repository install remains available as an alternative:

git clone https://github.com/Bandwidth/bw_labs_sdks.git
pip install ./bw_labs_sdks/python

TypeScript/Node, install from npm:

npm install @bandwidth-labs/bw-stt@^0.2.0

Live transcription (instant mode)

Stream audio and print words as they land. Segments are final the moment they arrive; the assembler joins them into a running transcript.

from bw_stt import BwSttClient, TranscriptAssembler

client = BwSttClient()
transcript = TranscriptAssembler()
with client.connect(encoding="linear16", sample_rate=16000) as session:
    session.on_segment(transcript.push)
    for _segment in session.stream_file("call.wav"):
        print("\r" + transcript.text, end="", flush=True)
    closed = session.close_stream()
print("\r" + transcript.text)
import { BwSttClient } from "@bandwidth-labs/bw-stt";

const client = new BwSttClient();
const session = await client.connect({ encoding: "linear16", sampleRate: 16000 });
session.on("segment", (segment) => process.stdout.write(segment.text));
for await (const segment of session.streamFile("call.wav")) void segment;
await session.closeStream();

Transcripts on your schedule (demand mode)

In demand mode nothing is delivered until you ask. Stream audio, then call the finalize helper at each boundary you care about, such as the end of a caller turn. Each call returns one finalized transcript per channel.

with client.connect(mode="demand") as session:
    session.send_audio(turn_audio)
    transcripts = session.finalize_transcript()  # one Transcript per channel
    print(transcripts[0].text)
const session = await client.connect({ mode: "demand" });
session.sendAudio(turnAudio);
const transcripts = await session.finalizeTranscript();
console.log(transcripts[0].text);

Whole recordings (Transcribe)

One call for a complete recording of up to five minutes. The result carries the full text, word timestamps, and segments.

result = client.transcribe("call.wav")
print(result.text)
for word in result.words[:5]:
    print(word.word, word.start, word.end)
import { readFile } from "node:fs/promises";

const result = await client.transcribe(await readFile("call.wav"));
console.log(result.text);

Long recordings (async transcription)

For recordings over five minutes and up to 30 minutes, submit an asynchronous job. Use get for the current status, wait to poll until the job reaches a terminal status, and delete to remove the job and its stored result.

job = client.transcriptions.submit("call.wav")
current = client.transcriptions.get(job.id)  # TranscriptionJob: status, progress
result = client.transcriptions.wait(job.id)  # Transcription; raises TranscriptionJobError if the job fails
print(result.text)
client.transcriptions.delete(job.id)
import { readFile } from "node:fs/promises";

const job = await client.transcriptions.submit({ audio: await readFile("call.wav"), raw: false });
const current = await client.transcriptions.get(job.id);
const result = await client.transcriptions.wait(job.id);
console.log(result.text);
await client.transcriptions.delete(job.id);

wait polls every 2 seconds and gives up after 600 seconds by default, raising TranscriptionTimeoutError; both values are configurable. Uploads are buffered in memory before sending, up to the 512 MiB limit. Raw audio submitted with multichannel=true must declare channels=2; WAV files and audio_url submissions let the service read the channel count itself.

Redaction and keywords

Both SDKs expose the PII and keyword options as typed parameters on connect and transcribe. Redaction is available in demand and Transcribe modes.

result = client.transcribe(
    "call.wav",
    redact_pii=True,
    redact_pii_return=True,
    keywords=["Bandwidth", "porting"],
)
for entity in result.redacted_entities:
    print(entity.kind, entity.token, entity.text)
const result = await client.transcribe(audio, {
  redactPii: true,
  redactPiiReturn: true,
  keywords: ["Bandwidth", "porting"],
});

For event handling, error taxonomy, browser usage, codec options, and complete examples, see the language guides in the repository.