Endpoints
Realtime
Mint a short-lived session token, then stream PCM16 audio over a WebSocket and receive live transcripts.
Realtime transcription is a two-step flow: your server mints a short-lived session token with POST /v2/realtime/token, then the client (browser, mobile app, or your backend) opens the WebSocket with that token and streams raw PCM16 audio. Transcripts come back as JSON events while the audio is still playing.
Never expose an
rtvk_ API key to end-user devices. The token endpoint exists so only the short-lived session token ever reaches the client.Mint a realtime token
POST
/v2/realtime/tokenCreate a short-lived token for one realtime sessionRequest body
| Field | Type | Default | Description |
|---|---|---|---|
| model | string | whisper-voicekit-realtime-pro | Realtime model id: whisper-voicekit-realtime-pro or whisper-voicekit-realtime. A non-realtime model returns 400 bad_model. |
| sample_rate | integer, 8000 to 48000 | 16000 | Sample rate of the PCM16 audio you will stream. |
| language_code | string or null | null | Language of the speech, for example en. Optional. |
| medical_mode | boolean | false | Use the medical domain model for the session. |
| expires_in | integer, 60 to 3600 | 900 | Token lifetime in seconds. The token must be redeemed on the WebSocket before it expires. |
| estimated_duration_sec | integer or null | null | Estimated session length for the pre-flight credit check; may fail early with 402 v2_billing_required. |
Response
| Field | Type | Description |
|---|---|---|
| token | string | Session token to pass as the token query parameter on the WebSocket. |
| websocket_url | string | The WebSocket endpoint, wss://api.realtimevoicekit.com/v2/realtime/ws. |
| expires_at | string | ISO 8601 expiry of the token. |
| model | string | The resolved model id. |
| sample_rate | integer | Echo of the requested sample rate. Pass the same value when connecting. |
Errors
| Status | Code | When |
|---|---|---|
| 400 | unknown_model | model is not a catalog id. |
| 400 | bad_model | model is valid but not a realtime model. |
| 402 | v2_billing_required | Credit exhausted or the estimate exceeds the balance. |
curl -X POST https://api.realtimevoicekit.com/v2/realtime/token \
-H "Authorization: Bearer rtvk_your_api_key" \
-H "Content-Type: application/json" \
-d '{"model": "whisper-voicekit-realtime", "sample_rate": 16000, "language_code": "en"}'Realtime WebSocket
WSS
/v2/realtime/wsStream PCM16 audio, receive transcript eventsQuery parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| token | string | required | Session token from POST /v2/realtime/token. |
| sample_rate | integer, 8000 to 48000 | 16000 | Must match the audio you send. |
| model | string | whisper-voicekit-realtime-pro | Realtime model id. Use the same model you minted the token with. |
| language_code | string | none | Optional language of the speech. An unsupported value ends the session with an error event. |
| medical_mode | boolean | false | Use the medical domain model. |
Sending audio
- Send audio as binary WebSocket frames containing raw 16-bit little-endian PCM, mono, at the declared
sample_rate. Chunks of roughly 50 to 200 ms work well. - To end the session cleanly, send a JSON text frame containing
{"type": "stop"}. The server flushes final transcripts, sendsdone, and closes.
Server events
| type | Payload | Meaning |
|---|---|---|
| ready | none | The session is live; start streaming audio. |
| transcript | text, end_of_turn, formatted, words | A live transcript update. end_of_turn is true when the speaker finished a turn; formatted is true when punctuation and casing are final; words carry text, start, end (milliseconds), and confidence. |
| reconnect | message | The session reached the maximum duration (55 minutes). Mint a new token and open a fresh connection to continue. |
| error | message | Something went wrong, for example an unsupported language. The server closes after this event. |
| done | none | Final event before a clean close. |
{
"type": "transcript",
"text": "welcome everyone to the weekly sync",
"end_of_turn": false,
"formatted": false,
"words": [
{ "text": "welcome", "start": 480, "end": 900, "confidence": 0.99 },
{ "text": "everyone", "start": 940, "end": 1420, "confidence": 0.98 }
]
}Close codes
| Code | Meaning |
|---|---|
| 4401 | The token is missing, expired, or not a realtime session token. |
| 4400 | The model query parameter is not a valid realtime model. |
Billing: the session is metered per elapsed second at the model's hourly session rate, from accept to close. See Models and pricing.
End-to-end example
// 1) On your server: mint a session token.
const tokenRes = await fetch("https://api.realtimevoicekit.com/v2/realtime/token", {
method: "POST",
headers: {
Authorization: "Bearer rtvk_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({ model: "whisper-voicekit-realtime", sample_rate: 16000 }),
}).then((r) => r.json());
// 2) On the client: connect with the token and stream PCM16 audio.
const url =
tokenRes.websocket_url +
"?token=" + encodeURIComponent(tokenRes.token) +
"&model=whisper-voicekit-realtime&sample_rate=16000";
const ws = new WebSocket(url);
ws.binaryType = "arraybuffer";
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === "transcript") console.log(msg.text);
if (msg.type === "done") ws.close();
};
// Send each captured audio chunk (Int16Array PCM at 16 kHz):
// ws.send(pcmChunk.buffer);
// Finish the session:
// ws.send(JSON.stringify({ type: "stop" }));