---
title: "Unified Real-Time Speech-to-Text API for Multiple Providers"
description: "Use one real-time speech-to-text API for multiple transcription providers. Stream audio over WebSocket or use OpenAI- and ElevenLabs-compatible SDKs with AllModels."
canonical: "https://allmodels.io/guides/universal-stt-api"
markdown: "https://allmodels.io/guides/universal-stt-api.md"
author: "AllModels"
datePublished: "2026-10-15"
dateModified: "2026-10-15"
---

# One API for real-time speech-to-text providers

Transcribe with STT models from multiple providers through AllModels. Stream audio over WebSocket, use an OpenAI- or ElevenLabs-compatible SDK, and switch models without rebuilding your transcription pipeline.

> AllModels is an independent service and is not affiliated with, endorsed by, or sponsored by the providers whose models it routes to.

## What a unified speech-to-text API is

A unified speech-to-text (STT) API is a single integration that can transcribe audio with models from many different providers. Instead of writing one client for Deepgram, another for AssemblyAI, another for Soniox and another for OpenAI, your application talks to one endpoint with one API key. The model you choose decides which provider transcribes the audio. AllModels is a unified STT API of this kind: you send a model ID such as `deepgram/nova-3`, `assemblyai/universal-3-5-pro-realtime` or `soniox/stt-rt-v5`, and AllModels routes the audio to that provider and returns the transcript.

### How AllModels works

Every model in the [AllModels STT catalogue](https://allmodels.io/models?type=stt) has a `provider/model` ID. You authenticate once with an AllModels API key, which replaces the separate keys and billing accounts you would otherwise keep with each provider. AllModels then offers three ways to call the same models:

- **Native WebSocket** at `wss://api.allmodels.io/v1/stt`. You send raw audio frames as they are captured and receive `stt.transcript.partial` and `stt.transcript.final` events in one normalized format, whichever provider is behind the model.
- **OpenAI-compatible** at `https://api.allmodels.io/oai`. Point the official OpenAI SDK at this base URL and keep calling `audio.transcriptions.create` for files, or its realtime client for live audio.
- **ElevenLabs-compatible** at `https://api.allmodels.io/el`. Point the official ElevenLabs SDK at this base URL and keep calling its speech-to-text methods, including realtime transcription.

All three reach the same catalogue. If your codebase already uses the OpenAI or ElevenLabs SDK, you can move to AllModels by changing the base URL and API key.

### Live audio and complete files

For microphones, calls and voice agents, stream audio over a WebSocket and read partial transcripts while the speaker is still talking. When the complete recording already exists, upload it in one HTTP request and get the full transcript back. To use a different STT model, change the model ID; your API key, endpoint and client code stay the same.

## Transcribe real-time audio from any client

Choose a client, a mode and a language. Highlighted lines are the AllModels base URL and the model values you change to try another model.

### Native WebSocket, streaming — JavaScript · Node.js · ws

Client: Native · Mode: Streaming · Language: JS

Connect to `wss://api.allmodels.io/v1/stt`, send 16 kHz PCM audio as binary frames and read partial and final transcripts. [STT docs](https://allmodels.io/docs/speech-to-text).

```javascript
import { readFile } from "node:fs/promises";
import WebSocket from "ws";

const url = new URL("wss://api.allmodels.io/v1/stt");
url.searchParams.set("model", "deepgram/nova-3");
url.searchParams.set("audio_format", "pcm_16000");
url.searchParams.set("language", "en");
url.searchParams.set("commit_strategy", "manual");

const ws = new WebSocket(url, {
  headers: { Authorization: `Bearer ${process.env.ALLMODELS_API_KEY}` }
});

ws.on("message", (data) => {
  const event = JSON.parse(data.toString());
  if (event.type === "stt.transcript.partial") console.log("partial:", event.text);
  if (event.type === "stt.transcript.final") {
    console.log("final:", event.text);
    ws.send(JSON.stringify({ type: "stt.session.close" }));
  }
});

ws.on("open", async () => {
  const audio = await readFile("speech-16khz.pcm");
  for (let offset = 0; offset < audio.length; offset += 3200) {
    ws.send(audio.subarray(offset, offset + 3200));
  }
  ws.send(JSON.stringify({ type: "stt.audio.commit" }));
});
```

### Native WebSocket, streaming — Python · websockets

Client: Native · Mode: Streaming · Language: Python

Connect to `wss://api.allmodels.io/v1/stt`, send 16 kHz PCM audio as binary frames and read partial and final transcripts. [STT docs](https://allmodels.io/docs/speech-to-text).

```python
import asyncio
import json
import os
from pathlib import Path
from urllib.parse import urlencode

import websockets

async def main():
    query = urlencode({
        "model": "deepgram/nova-3",
        "audio_format": "pcm_16000",
        "language": "en",
        "commit_strategy": "manual",
    })
    headers = {"Authorization": f"Bearer {os.environ['ALLMODELS_API_KEY']}"}
    async with websockets.connect(
        f"wss://api.allmodels.io/v1/stt?{query}", additional_headers=headers
    ) as ws:
        audio = Path("speech-16khz.pcm").read_bytes()
        for offset in range(0, len(audio), 3200):
            await ws.send(audio[offset:offset + 3200])
        await ws.send(json.dumps({"type": "stt.audio.commit"}))

        async for message in ws:
            event = json.loads(message)
            if event["type"] == "stt.transcript.partial":
                print("partial:", event["text"])
            elif event["type"] == "stt.transcript.final":
                print("final:", event["text"])
                break

asyncio.run(main())
```

### HTTP, single request — JavaScript · Node.js · fetch

Client: Native · Mode: Request · Language: JS

Already have the recording? POST it to `https://api.allmodels.io/oai/audio/transcriptions` and read the transcript. [STT docs](https://allmodels.io/docs/speech-to-text).

```javascript
import { readFile } from "node:fs/promises";

const form = new FormData();
form.set("model", "deepgram/nova-3");
form.set("language", "en");
form.set("file", new Blob([await readFile("call.wav")], { type: "audio/wav" }), "call.wav");

const response = await fetch("https://api.allmodels.io/oai/audio/transcriptions", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.ALLMODELS_API_KEY}` },
  body: form
});

if (!response.ok) throw new Error(await response.text());
const transcript = await response.json();
console.log(transcript.text);
```

### HTTP, single request — Python · requests

Client: Native · Mode: Request · Language: Python

Already have the recording? POST it to `https://api.allmodels.io/oai/audio/transcriptions` and read the transcript. [STT docs](https://allmodels.io/docs/speech-to-text).

```python
import os
import requests

with open("call.wav", "rb") as audio:
    response = requests.post(
        "https://api.allmodels.io/oai/audio/transcriptions",
        headers={"Authorization": f"Bearer {os.environ['ALLMODELS_API_KEY']}"},
        data={"model": "deepgram/nova-3", "language": "en"},
        files={"file": ("call.wav", audio, "audio/wav")},
        timeout=60,
    )

response.raise_for_status()
print(response.json()["text"])
```

### OpenAI SDK, realtime — JavaScript · openai

Client: OpenAI SDK · Mode: Streaming · Language: JS

Set the OpenAI SDK base URL to `https://api.allmodels.io/oai`, open a realtime transcription session and send 24 kHz PCM audio. [OpenAI realtime docs](https://allmodels.io/docs/openai/realtime).

```javascript
import { once } from "node:events";
import { readFile } from "node:fs/promises";
import OpenAI from "openai";
import { OpenAIRealtimeWebSocket } from "openai/realtime/websocket";

const client = new OpenAI({
  apiKey: process.env.ALLMODELS_API_KEY,
  baseURL: "https://api.allmodels.io/oai"
});
const realtime = await OpenAIRealtimeWebSocket.create(client, {
  model: "openai/gpt-realtime-whisper"
});
if (realtime.socket.readyState !== 1) await once(realtime.socket, "open");

realtime.on("conversation.item.input_audio_transcription.delta", ({ delta }) => {
  process.stdout.write(delta);
});
realtime.on("conversation.item.input_audio_transcription.completed", ({ transcript }) => {
  console.log("\nfinal:", transcript);
  realtime.close();
});

realtime.send({
  type: "session.update",
  session: {
    type: "transcription",
    audio: {
      input: {
        format: { type: "audio/pcm", rate: 24000 },
        transcription: { model: "openai/gpt-realtime-whisper", language: "en" },
        turn_detection: null
      }
    }
  }
});

const audio = await readFile("speech-24khz.pcm");
for (let offset = 0; offset < audio.length; offset += 4800) {
  realtime.send({
    type: "input_audio_buffer.append",
    audio: audio.subarray(offset, offset + 4800).toString("base64")
  });
}
realtime.send({ type: "input_audio_buffer.commit" });
```

### OpenAI SDK, realtime — Python · openai

Client: OpenAI SDK · Mode: Streaming · Language: Python

Set the OpenAI SDK base URL to `https://api.allmodels.io/oai`, open a realtime transcription session and send 24 kHz PCM audio. [OpenAI realtime docs](https://allmodels.io/docs/openai/realtime).

```python
import asyncio
import base64
import os
from pathlib import Path

from openai import AsyncOpenAI

async def main():
    client = AsyncOpenAI(
        api_key=os.environ["ALLMODELS_API_KEY"],
        base_url="https://api.allmodels.io/oai",
    )
    async with client.realtime.connect(
        model="openai/gpt-realtime-whisper",
        extra_query={"intent": "transcription"},
    ) as connection:
        await connection.session.update(session={
            "type": "transcription",
            "audio": {
                "input": {
                    "format": {"type": "audio/pcm", "rate": 24000},
                    "transcription": {"model": "openai/gpt-realtime-whisper", "language": "en"},
                    "turn_detection": None,
                }
            },
        })

        audio = Path("speech-24khz.pcm").read_bytes()
        for offset in range(0, len(audio), 4800):
            chunk = base64.b64encode(audio[offset:offset + 4800]).decode("ascii")
            await connection.input_audio_buffer.append(audio=chunk)
        await connection.input_audio_buffer.commit()

        async for event in connection:
            if event.type == "conversation.item.input_audio_transcription.delta":
                print(event.delta, end="", flush=True)
            elif event.type == "conversation.item.input_audio_transcription.completed":
                print("\nfinal:", event.transcript)
                break

asyncio.run(main())
```

### OpenAI SDK, single request — JavaScript · openai

Client: OpenAI SDK · Mode: Request · Language: JS

Set the OpenAI SDK base URL to `https://api.allmodels.io/oai` and transcribe a complete file with `audio.transcriptions.create`. [OpenAI transcription docs](https://allmodels.io/docs/openai/transcription).

```javascript
import { createReadStream } from "node:fs";
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.ALLMODELS_API_KEY,
  baseURL: "https://api.allmodels.io/oai"
});

const transcript = await client.audio.transcriptions.create({
  file: createReadStream("call.wav"),
  model: "deepgram/nova-3",
  language: "en"
});

console.log(transcript.text);
```

### OpenAI SDK, single request — Python · openai

Client: OpenAI SDK · Mode: Request · Language: Python

Set the OpenAI SDK base URL to `https://api.allmodels.io/oai` and transcribe a complete file with `audio.transcriptions.create`. [OpenAI transcription docs](https://allmodels.io/docs/openai/transcription).

```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["ALLMODELS_API_KEY"],
    base_url="https://api.allmodels.io/oai",
)

with open("call.wav", "rb") as audio:
    transcript = client.audio.transcriptions.create(
        file=audio,
        model="deepgram/nova-3",
        language="en",
    )

print(transcript.text)
```

### ElevenLabs SDK, realtime — JavaScript · @elevenlabs/elevenlabs-js

Client: ElevenLabs SDK · Mode: Streaming · Language: JS

Set the ElevenLabs SDK base URL to `https://api.allmodels.io/el` and stream 16 kHz PCM audio through its realtime speech-to-text client. [ElevenLabs realtime docs](https://allmodels.io/docs/elevenlabs/realtime).

```javascript
import { readFile } from "node:fs/promises";
import { AudioFormat, CommitStrategy, ElevenLabsClient, RealtimeEvents } from "@elevenlabs/elevenlabs-js";

const client = new ElevenLabsClient({
  apiKey: process.env.ALLMODELS_API_KEY,
  baseUrl: "https://api.allmodels.io/el"
});

const connection = await client.speechToText.realtime.connect({
  modelId: "deepgram/nova-3",
  audioFormat: AudioFormat.PCM_16000,
  sampleRate: 16000,
  languageCode: "en",
  commitStrategy: CommitStrategy.MANUAL
});

connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, ({ text }) => console.log("partial:", text));
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, ({ text }) => {
  console.log("final:", text);
  connection.close();
});

connection.on(RealtimeEvents.SESSION_STARTED, async () => {
  const audio = await readFile("speech-16khz.pcm");
  for (let offset = 0; offset < audio.length; offset += 3200) {
    connection.send({ audioBase64: audio.subarray(offset, offset + 3200).toString("base64") });
  }
  connection.commit();
});
```

### ElevenLabs SDK, realtime — Python · elevenlabs

Client: ElevenLabs SDK · Mode: Streaming · Language: Python

Set the ElevenLabs SDK base URL to `https://api.allmodels.io/el` and stream 16 kHz PCM audio through its realtime speech-to-text client. [ElevenLabs realtime docs](https://allmodels.io/docs/elevenlabs/realtime).

```python
import asyncio
import base64
import os
from pathlib import Path

from elevenlabs import AudioFormat, CommitStrategy, ElevenLabs, RealtimeEvents

async def main():
    client = ElevenLabs(
        api_key=os.environ["ALLMODELS_API_KEY"],
        base_url="https://api.allmodels.io/el",
    )
    connection = await client.speech_to_text.realtime.connect({
        "model_id": "deepgram/nova-3",
        "audio_format": AudioFormat.PCM_16000,
        "sample_rate": 16000,
        "language_code": "en",
        "commit_strategy": CommitStrategy.MANUAL,
    })

    finished = asyncio.Event()

    def on_committed(event):
        print("final:", event["text"])
        finished.set()

    connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, lambda event: print("partial:", event["text"]))
    connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, on_committed)

    audio = Path("speech-16khz.pcm").read_bytes()
    for offset in range(0, len(audio), 3200):
        chunk = base64.b64encode(audio[offset:offset + 3200]).decode("ascii")
        await connection.send({"audio_base_64": chunk})
    await connection.commit()
    await finished.wait()
    await connection.close()

asyncio.run(main())
```

### ElevenLabs SDK, single request — JavaScript · @elevenlabs/elevenlabs-js

Client: ElevenLabs SDK · Mode: Request · Language: JS

Set the ElevenLabs SDK base URL to `https://api.allmodels.io/el` and transcribe a complete file. The JavaScript SDK checks model IDs, so use an ID it recognizes such as `scribe_v2`. [ElevenLabs transcription docs](https://allmodels.io/docs/elevenlabs/transcription).

```javascript
import { File } from "node:buffer";
import { readFile } from "node:fs/promises";
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const client = new ElevenLabsClient({
  apiKey: process.env.ALLMODELS_API_KEY,
  baseUrl: "https://api.allmodels.io/el"
});

const bytes = await readFile("call.wav");
const transcript = await client.speechToText.convert({
  file: new File([bytes], "call.wav", { type: "audio/wav" }),
  modelId: "scribe_v2",
  languageCode: "en"
});

console.log(transcript.text);
```

### ElevenLabs SDK, single request — Python · elevenlabs

Client: ElevenLabs SDK · Mode: Request · Language: Python

Set the ElevenLabs SDK base URL to `https://api.allmodels.io/el` and transcribe a complete file with any AllModels STT model ID. [ElevenLabs transcription docs](https://allmodels.io/docs/elevenlabs/transcription).

```python
import os
from elevenlabs.client import ElevenLabs

client = ElevenLabs(
    api_key=os.environ["ALLMODELS_API_KEY"],
    base_url="https://api.allmodels.io/el",
)

with open("call.wav", "rb") as audio:
    transcript = client.speech_to_text.convert(
        file=audio,
        model_id="deepgram/nova-3",
        language_code="en",
    )

print(transcript.text)
```

## Use the client your team already knows

### OpenAI-compatible

Endpoint: `https://api.allmodels.io/oai`

Already using the OpenAI SDK? Set its base URL to AllModels and keep calling `audio.transcriptions.create` or the realtime client, now with an AllModels model ID.

- [Read the OpenAI transcription docs](https://allmodels.io/docs/openai/transcription)

### ElevenLabs-compatible

Endpoint: `https://api.allmodels.io/el`

Already using the ElevenLabs SDK? Set its base URL to AllModels and keep using its convert and realtime speech-to-text methods, now with an AllModels model ID.

- [Read the ElevenLabs transcription docs](https://allmodels.io/docs/elevenlabs/transcription)

## Real-time STT API basics

### What is a unified speech-to-text API?

A unified STT API gives applications one integration surface for multiple transcription models. With AllModels, the chosen model ID determines the provider while authentication and the core request flow stay the same.

### Does AllModels support real-time transcription?

Yes. The native interface streams over WebSocket at `/v1/stt` and returns partial and final transcripts as normalized `stt.*` events. The OpenAI and ElevenLabs SDKs stream through their own realtime clients. Streaming support varies by model.

### Can I use every provider feature?

Yes. Common settings use the standard fields, and any provider-specific setting, such as diarization settings, goes in `provider_options` and is passed directly to the provider.

### How do I compare providers?

Browse the [STT catalogue](https://allmodels.io/models?type=stt) to compare available models, streaming support, pricing and API examples before changing the model ID in your application.

## One integration in three steps

1. **Choose a model.** Pick an STT model from the [live catalogue](https://allmodels.io/models?type=stt) by its `provider/model` ID.
2. **Use one API key.** Authenticate with AllModels instead of a separate key for every provider.
3. **Stream or upload.** Stream audio over WebSocket for live transcripts, or upload a complete file over HTTP.

## Start with one STT integration.

Choose a model now and keep the freedom to change it later.

- [Start free](https://dash.allmodels.io/signup)
- [Browse STT models](https://allmodels.io/models?type=stt)
- [Read the AllModels documentation](https://allmodels.io/docs)
- [View the canonical HTML guide](https://allmodels.io/guides/universal-stt-api)
