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 parameterTypeRequiredDescription
usage_typeStringYesMust be vt for Voice Translation.
expiration_ttlIntegerNoLifetime 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 the authorization query 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 ready can take longer than on the other endpoints. Wait for ready before sending audio.
  • Audio: after ready, send the speech as binary messages in the format declared in config.audio (pcm_s16le or opus, 16 kHz, mono). Each message can be at most 65,536 bytes.
  • Finishing: close the WebSocket.

Client hello

VTClientHello

The first message sent by the client to initiate a VT connection.

FieldTypeRequiredDefaultDescription
configVTConfigyesVoice translation session configuration
metadataobjectnoUser-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

FieldTypeRequiredDefaultDescription
audioVTAudioConfigyesAudio configuration
source_languagestringyesSource language code (e.g. 'en-US')
target_languagestringyesTarget language code (e.g. 'fr-FR')
voice"male" | "female"yesVoice gender ('male' or 'female')
featuresVTFeatures | nullnonullOptional feature flags for the session
vocabularyarray of string | nullnonullCustom vocabulary terms
metadataobject | nullnonullOptional session metadata
translation_dictionaryarray of VTTranslationDictionaryEntry | nullnonullCustom translation dictionary entries
transcriptVTTranscriptConfig | nullnonullTranscript output configuration

VTAudioConfig

FieldTypeRequiredDefaultDescription
formatVTSupportedAudioFormatsno"pcm_s16le"Audio format.
sample_rateintegeryesSample rate in Hz. Only 16000 is supported.
channelsintegerno1Number of channels. Only 1 is supported.

VTSupportedAudioFormats

Audio formats supported by the VT service.

Allowed values: "pcm_s16le", "opus"

VTFeatures

FieldTypeRequiredDefaultDescription
background_voice_cancellationbooleannofalseEnable background voice cancellation

VTTranscriptConfig

FieldTypeRequiredDefaultDescription
interimboolean | nullnonullEmit interim transcripts
finalboolean | nullnonullEmit final transcripts
translateboolean | nullnonullEmit translated transcripts

VTTranslationDictionaryEntry

FieldTypeRequiredDefaultDescription
sourcestringyesSource term
targetstringyesTranslated 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)

The first response sent by the server to the client. Successful handshake response format.

FieldTypeRequiredDefaultDescription
typestringno"ready"Response type
request_idstring | nullnonullRequest ID if available
tracks_msarray of integer | nullnonullDelays in ms of the decoders producing partial results. Each partial word's src is one of these values.
metadataobject | nullnonullUser-provided metadata, echoed back. Omitted entirely when the service's ClientHello carries no metadata field.

ErrorResponse (error)

Error response schema following the standard format.

FieldTypeRequiredDefaultDescription
typestringno"error"Response type
request_idstring | nullnonullRequest ID if available
errorErrorInfoyesError information

ErrorInfo

Error information structure.

FieldTypeRequiredDefaultDescription
codestringyesError code identifier
status_codeintegeryesHTTP status code
messagestringyesHuman-readable error message
detailsobject | nullnonullOptional 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"
  }
}
FieldTypeDescription
transcript.textstringTranscript text for this chunk.
transcript.finalbooleanfalse for interim results, true for the final transcript of an utterance.
transcript.startstring (ISO 8601)Start of the chunk, in UTC.
transcript.durationintegerDuration of the chunk in milliseconds.
transcript.utterance_idstringLinks this transcript to the utterance's final transcript and translation.
transcript.reference_idstringYour reference ID, echoed back, if you sent one.
{
  "translate": {
    "text": "¿Hola, cómo estás?",
    "final": true,
    "utterance_id": "daslkndlkans",
    "reference_id": "askdnl"
  }
}
FieldTypeDescription
translate.textstringTranslated text.
translate.finalbooleanfalse for interim results.
translate.utterance_idstringLinks this translation to its transcript.
translate.reference_idstringYour 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.codestatus_codeWhen
invalid_client_hello400config 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_error4xxKrisp rejected the session parameters. details.fields lists each rejected field as field / message (and value when available).
vt_concurrency_limit_exceeded4xxYour account reached its limit of simultaneous voice-translation sessions.
vt_usage_limit_exceeded4xxYour account reached its voice-translation usage limit.
internal_server_error500The 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.

Did this page help you?