Skip to main content
Lesson 8 of 18 · Realtime API and Voice Agents

Automatic Translation

Lesson 8 of 18 Updated November 3, 2026 Developer
On this page
  1. Two needs, two tools
  2. Translating a recording
  3. Interpreting live speech
  4. Key takeaways

Lesson rewritten November 3, 2026. It previously relied on the /v1/audio/translations endpoint and whisper-1, both deprecated and discontinued on February 26, 2027, as well as a repurposed Realtime assistant session acting as an interpreter. OpenAI now offers two paths: for recordings, transcription in the original language with gpt-transcribe, followed by text translation; for live speech, a dedicated translation session with gpt-realtime-translate. The code has been verified with SDK openai 3.42.1 and the websocket-client library. Sources: File transcription · Realtime translation · Deprecations.

Two needs, two tools

Translating audio covers two very different scenarios, and OpenAI handles them with different tools:

NeedTool as of November 2026Result
A recording to translate (meeting, podcast, archived call)gpt-transcribe to transcribe in the original language, then a text model to translateTranslated text in your target language
Live speech to interpret (call, conference, class)Realtime translation session with gpt-realtime-translateTranslated audio and transcripts, generated as speech occurs
Legacy path: /v1/audio/translations with whisper-1Deprecated, discontinued February 26, 2027English text only

OpenAI’s guide emphasizes one point: simply changing the model ID in a /v1/audio/translations request does not migrate anything. The old endpoint, which could only translate to English, has no direct replacement.

Translating a recording

This method first transcribes faithfully in the spoken language, then translates the text. It works for any target language—unlike the old endpoint, which produced only English—and gives you both texts, which is useful for verification:

from openai import OpenAI

client = OpenAI()


def translate_recording(path: str, target_language: str) -> dict[str, str]:
    """Transcribes a recording in its original language, then translates the text."""
    with open(path, "rb") as f:
        transcription = client.audio.transcriptions.create(model="gpt-transcribe", file=f)

    response = client.responses.create(
        model="gpt-6-luna",
        instructions=(
            f"Translate the text provided by the user into {target_language}. "
            "Keep the tone and style. Respond only with the translation."
        ),
        input=transcription.text,
    )
    return {"original": transcription.text, "translation": response.output_text}


result = translate_recording("reunion_fr.mp3", "German")
print(result["translation"])

Two choices deserve explanation. The translation instruction goes in instructions, while the transcription arrives as plain data in input: a recording can contain anything, including a phrase that looks like a command, and it must not be able to modify the instruction. The gpt-6-luna model is what OpenAI recommends for large-scale, cost-sensitive processing; for delicate legal or technical text, choose a more capable model, such as gpt-6.1-sol.

Interpreting live speech

To translate while someone is speaking, OpenAI offers a special kind of Realtime session. The guide clearly distinguishes it from a voice agent session:

Voice agent sessionTranslation session
Connects to /v1/realtimeConnects to /v1/realtime/translations
The model acts as an assistantThe model acts as an interpreter
Conversation and response cycle (response.create)Continuous stream from incoming audio, no response.create
Can call toolsProduces translated audio and transcripts

The transport depends on where the audio arrives. In a browser, WebRTC sends the microphone input and receives the translated voice as audio tracks; your server creates a short-lived client secret for this via /v1/realtime/translations/client_secrets, so your API key never leaves the server. On the server side, when the audio already arrives raw (a phone stream, a capture), a WebSocket connection is enough:

import base64
import json
import os

import websocket  # pip install websocket-client

ws = websocket.WebSocket()
ws.connect(
    "wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
    header=[
        f"Authorization: Bearer {os.environ['OPENAI_API_KEY']}",
        "OpenAI-Safety-Identifier: hashed-user-id",  # hashed identifier of your user
    ],
)

# Output language of the interpreter
ws.send(json.dumps({"type": "session.update", "session": {"audio": {"output": {"language": "en"}}}}))


def send_audio(pcm16: bytes) -> None:
    """Appends a chunk of source audio: 16-bit PCM, mono, 24 kHz."""
    ws.send(json.dumps({"type": "session.input_audio_buffer.append", "audio": base64.b64encode(pcm16).decode()}))

While you send the audio, including silences, the session returns events to process on the fly: session.output_audio.delta carries the translated audio in base64, session.output_transcript.delta the translated text, and session.input_transcript.delta the transcription of the original. When the source stops, send session.close: the service finishes the current translation, then responds with session.closed.

translation: list[str] = []
while True:
    event = json.loads(ws.recv())
    if event["type"] == "session.output_transcript.delta":
        translation.append(event["delta"])
    elif event["type"] == "error":
        raise RuntimeError(f"Translation error: {event['error']['code']}")
    elif event["type"] == "session.closed":
        break
ws.close()
print("".join(translation))

Do not neglect the error event: a rejected key does not fail the connection itself; it arrives just afterward as an error event with code invalid_api_key (observed November 3, 2026). In production, reception runs in parallel with sending, in a separate thread or task, and the translated audio goes to the player or phone line as it arrives: the official guide provides a complete version, including audio playback.

Key takeaways

  • /v1/audio/translations and whisper-1 shut down on February 26, 2027, with no direct replacement: changing the model is not enough
  • For a recording: gpt-transcribe in the original language, then text translation by a text model, to any language
  • Keep the translation instruction in instructions and the transcription as plain data
  • For live speech: a translation session (/v1/realtime/translations, gpt-realtime-translate), which acts as the interpreter, without response.create
  • WebRTC in the browser, with a client secret created by the server; WebSocket on the server side, with 16-bit PCM audio at 24 kHz