Voice Translation API
Stream speech in one language over a WebSocket and receive it spoken in another, with optional transcripts and translations, in real time.
Stream speech in one language and receive it spoken in another, in realtime. You choose the source and target languages and the output voice, and can also tune the session with a custom vocabulary, a translation dictionary and transcript output.
See Authentication below for how to get a Voice Translation session token, and the API overview for the session protocol shared by all endpoints.
Try it
Paste an API key from the Developers Portal, pick the languages and a voice, press Start and speak. Use headphones so the translated speech does not reach your microphone. The demo creates a short-lived Voice Translation session token from your key and streams your microphone to wss://streaming.krisp.ai/vt. Sessions count toward your usage.
Authentication
On your backend, use your API key (master token) to create a temporary session token with usage_type set to vt, then open the WebSocket with the session token. Do not send the master token on the WebSocket.
curl -X POST \
'https://api.developers.krisp.ai/v2/sdk/tokens/session' \
-H 'Authorization: api-key YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"usage_type": "vt", "expiration_ttl": 100}'| Body parameter | Type | Required | Description |
|---|---|---|---|
usage_type | String | Yes | Must be vt for Voice Translation. |
expiration_ttl | Integer | No | Lifetime of the session token in minutes. Minimum 5, maximum 1440 (24 hours) for vt. Default 180 (3 hours). |
The response has the same format as the general session token: the session token is in data.session_key, and its expiry is in data.expires_at. The request fails with PRODUCT_NOT_ALLOWED if your account doesn't have access to Voice Translation, or VT_USAGE_LIMIT_EXCEEDED if it has reached its Voice Translation usage limit.
Use the returned session token as the API key when opening the WebSocket:
Authorization: Api-Key <session-token>If your client cannot set headers on a WebSocket handshake (for example, browsers), pass the same value as the authorization query parameter instead, URL-encoded:
wss://streaming.krisp.ai/vt?authorization=Api-Key%20<session-token>Connecting
- URL:
wss://streaming.krisp.ai/vt - Auth: a Voice Translation session token, sent as the
Authorization: Api-Key <session-token>header, or as theauthorizationquery parameter if headers can't be set. See Authentication. - First message: the client hello as a JSON text message, within 15 seconds of connecting. Before answering, the server starts a translation session for you, so
readycan take longer than on the other endpoints. Wait forreadybefore sending audio. - Audio: after
ready, send the speech as binary messages in the format declared inconfig.audio(pcm_s16leoropus, 16 kHz, mono). Each message can be at most 65,536 bytes. - Finishing: close the WebSocket.
Client hello
VTClientHello
VTClientHelloThe first message sent by the client to initiate a VT connection.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
config | VTConfig | yes | Voice translation session configuration | |
metadata | object | no | User-provided metadata (max 4KB when JSON-encoded) |
The top-level metadata must not exceed 4,096 bytes when JSON-encoded, and is echoed back in ready.
VTConfig
VTConfig| Field | Type | Required | Default | Description |
|---|---|---|---|---|
audio | VTAudioConfig | yes | Audio configuration | |
source_language | string | yes | Source language code (e.g. 'en-US') | |
target_language | string | yes | Target language code (e.g. 'fr-FR') | |
voice | "male" | "female" | yes | Voice gender ('male' or 'female') | |
features | VTFeatures | null | no | null | Optional feature flags for the session |
vocabulary | array of string | null | no | null | Custom vocabulary terms |
metadata | object | null | no | null | Optional session metadata |
translation_dictionary | array of VTTranslationDictionaryEntry | null | no | null | Custom translation dictionary entries |
transcript | VTTranscriptConfig | null | no | null | Transcript output configuration |
VTAudioConfig
VTAudioConfig| Field | Type | Required | Default | Description |
|---|---|---|---|---|
format | VTSupportedAudioFormats | no | "pcm_s16le" | Audio format. |
sample_rate | integer | yes | Sample rate in Hz. Only 16000 is supported. | |
channels | integer | no | 1 | Number of channels. Only 1 is supported. |
VTSupportedAudioFormats
VTSupportedAudioFormatsAudio formats supported by the VT service.
Allowed values: "pcm_s16le", "opus"
VTFeatures
VTFeatures| Field | Type | Required | Default | Description |
|---|---|---|---|---|
background_voice_cancellation | boolean | no | false | Enable background voice cancellation |
VTTranscriptConfig
VTTranscriptConfig| Field | Type | Required | Default | Description |
|---|---|---|---|---|
interim | boolean | null | no | null | Emit interim transcripts |
final | boolean | null | no | null | Emit final transcripts |
translate | boolean | null | no | null | Emit translated transcripts |
VTTranslationDictionaryEntry
VTTranslationDictionaryEntry| Field | Type | Required | Default | Description |
|---|---|---|---|---|
source | string | yes | Source term | |
target | string | yes | Translated target term |
Example:
{
"config": {
"audio": {"format": "pcm_s16le", "sample_rate": 16000, "channels": 1},
"source_language": "en-US",
"target_language": "fr-FR",
"voice": "female",
"features": {"background_voice_cancellation": true},
"vocabulary": ["Krisp"],
"translation_dictionary": [{"source": "Krisp", "target": "Krisp"}],
"transcript": {"interim": false, "final": true, "translate": true}
},
"metadata": {"call_id": "abc-123"}
}Server messages
GatewayServerHello (ready)
GatewayServerHello (ready)The first response sent by the server to the client. Successful handshake response format.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | string | no | "ready" | Response type |
request_id | string | null | no | null | Request ID if available |
tracks_ms | array of integer | null | no | null | Delays in ms of the decoders producing partial results. Each partial word's src is one of these values. |
metadata | object | null | no | null | User-provided metadata, echoed back. Omitted entirely when the service's ClientHello carries no metadata field. |
ErrorResponse (error)
ErrorResponse (error)Error response schema following the standard format.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | string | no | "error" | Response type |
request_id | string | null | no | null | Request ID if available |
error | ErrorInfo | yes | Error information |
ErrorInfo
ErrorInfoError information structure.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
code | string | yes | Error code identifier | |
status_code | integer | yes | HTTP status code | |
message | string | yes | Human-readable error message | |
details | object | null | no | null | Optional error details (e.g., {'hint': '...'}) |
Translation output
After ready, everything the translation session produces is forwarded to you unchanged:
- binary messages carry the translated speech. The Krisp demo client plays them as 16-bit PCM at 16 kHz.
- JSON text messages carry session output such as the transcripts enabled in
config.transcript.
Transcript and translation messages
When config.transcript enables them, the session sends transcripts of the source speech and translations of each utterance as JSON text messages. Use utterance_id to pair a transcript with its translation.
{
"transcript": {
"text": "Hello, how are you?",
"final": false,
"start": "2026-03-25T19:24:45.370+00:00",
"duration": 436,
"utterance_id": "daslkndlkans",
"reference_id": "askdnl"
}
}| Field | Type | Description |
|---|---|---|
transcript.text | string | Transcript text for this chunk. |
transcript.final | boolean | false for interim results, true for the final transcript of an utterance. |
transcript.start | string (ISO 8601) | Start of the chunk, in UTC. |
transcript.duration | integer | Duration of the chunk in milliseconds. |
transcript.utterance_id | string | Links this transcript to the utterance's final transcript and translation. |
transcript.reference_id | string | Your reference ID, echoed back, if you sent one. |
{
"translate": {
"text": "¿Hola, cómo estás?",
"final": true,
"utterance_id": "daslkndlkans",
"reference_id": "askdnl"
}
}| Field | Type | Description |
|---|---|---|
translate.text | string | Translated text. |
translate.final | boolean | false for interim results. |
translate.utterance_id | string | Links this translation to its transcript. |
translate.reference_id | string | Your reference ID, echoed back, if you sent one. |
Supported models
/vt has no model field. The session is configured by config: source_language and target_language, the output voice (male or female), audio, and optionally features, vocabulary, translation_dictionary and transcript. These values are checked when the translation session is started; parameters that Krisp rejects come back as a validation_error (see Errors).
Errors
Besides the common errors, these are specific to /vt. All of them are sent before ready, and the connection is then closed with close code 1008.
error.code | status_code | When |
|---|---|---|
invalid_client_hello | 400 | config is missing, a required field is missing or empty, voice is not male/female, audio.sample_rate is not 16000, audio.channels is not 1, audio.format is not in the list, or metadata is larger than 4 KB. |
validation_error | 4xx | Krisp rejected the session parameters. details.fields lists each rejected field as field / message (and value when available). |
vt_concurrency_limit_exceeded | 4xx | Your account reached its limit of simultaneous voice-translation sessions. |
vt_usage_limit_exceeded | 4xx | Your account reached its voice-translation usage limit. |
internal_server_error | 500 | The translation session could not be started. Retry after a few seconds. |
Supported languages
Source and target languages use BCP-47 codes such as en-US (not en). See Supported Languages for the list.
The list changes over time, so fetch it when a session starts instead of hard-coding it:
Call it from your backend with your API key (not a session token):
GET https://api.developers.krisp.ai/v2/sdk/voice-translation/languages
Authorization: api-key YOUR_API_KEY{
"success": true,
"code": 0,
"data": [
{ "name": "English (United States)", "language_code": "en-US" },
{ "name": "French", "language_code": "fr-FR" },
{ "name": "German", "language_code": "de-DE" }
],
"req_id": "..."
}Example
Streams a 16 kHz, mono, 16-bit PCM WAV file, saves the translated speech to translated.raw and prints the JSON messages. Requires pip install websockets.
import asyncio
import json
import sys
import wave
import websockets
SESSION_TOKEN = "YOUR_SESSION_TOKEN" # from POST /v2/sdk/tokens/session with usage_type "vt"
URL = "wss://streaming.krisp.ai/vt"
CHUNK_MS = 100
async def main(path: str) -> None:
headers = {"Authorization": f"Api-Key {SESSION_TOKEN}"}
async with websockets.connect(URL, additional_headers=headers) as ws:
await ws.send(json.dumps({
"config": {
"audio": {"format": "pcm_s16le", "sample_rate": 16000},
"source_language": "en-US",
"target_language": "fr-FR",
"voice": "female",
"transcript": {"final": True, "translate": True},
},
}))
hello = json.loads(await ws.recv())
if hello["type"] != "ready":
raise RuntimeError(hello)
async def send_audio() -> None:
with wave.open(path, "rb") as wf: # 16 kHz, mono, 16-bit PCM
frames_per_chunk = wf.getframerate() * CHUNK_MS // 1000
while chunk := wf.readframes(frames_per_chunk):
await ws.send(chunk)
await asyncio.sleep(CHUNK_MS / 1000) # realtime pace
await asyncio.sleep(5) # let the last translation arrive
await ws.close()
sender = asyncio.create_task(send_audio())
with open("translated.raw", "wb") as out:
async for message in ws:
if isinstance(message, bytes):
out.write(message)
else:
print(message)
await sender
asyncio.run(main(sys.argv[1]))Changelog
- 2026-10-01: Authentication now uses a Voice Translation session token from
GET /v2/sdk/voice-translation/session/token. - 2026-10-01: Page created: client hello (
VTConfig,VTAudioConfig,VTFeatures,VTTranscriptConfig,VTTranslationDictionaryEntry), output messages, errors.
Updated 2 days ago

