Elige tu API para ver cómo conectarte y qué eventos se usan durante la sesión.
Conectar un servidor a GPT-Live
Recomendamos WebRTC para las conexiones de audio con GPT-Live, incluidas las integraciones entre servidores.
También puedes usar WebSockets. La conexión WebSocket principal transmite audio y eventos JSON en ambos sentidos. Guarda la clave de API del proyecto en tu servidor de confianza.
Esta guía explica cómo transmitir audio a GPT-Live. Para supervisar o controlar una sesión existente, consulta Controles del lado del servidor. Para conectar un backend de razonamiento y herramientas a la API de Responses, consulta Modo WebSocket de Responses.
Autenticarse e iniciar la sesión
- Conéctate a
wss://api.openai.com/v1/live/sessionssin parámetros de consulta. Autentícate conAuthorization: Bearer $OPENAI_API_KEYe incluye los encabezados de conexión que se muestran en el ejemplo. - Envía
session.startcomo primer mensaje. Incluye el modelo, las instrucciones de conversación, el formato de audio, la voz y la configuración de delegación en el objetosession. - Espera a recibir
session.startedantes de enviar audio o comandos de la aplicación. Este evento contiene la configuración efectiva de la sesión y su ID.
El siguiente ejemplo usa la voz Marin, audio PCM16 a 24 kHz y un backend de Responses con búsqueda web. Usa instrucciones de conversación breves. Para configurar las instrucciones del backend, las herramientas y sus permisos, sigue la guía de Delegación y herramientas.
Transmitir audio con un SDK
Para Node.js, instala openai y ws con npm install openai ws y guarda el ejemplo de JavaScript como client.mjs. Para Python en macOS o Linux, instala openai[realtime] y guarda el ejemplo de Python como client.py. Define OPENAI_API_KEY en el entorno del servidor. Estos ejemplos requieren una versión del SDK compatible con Live. El ejemplo lee audio PCM16 mono sin procesar a 24 kHz de la entrada estándar y escribe el audio recibido en el mismo formato en la salida estándar. Conecta estos flujos a los sistemas de captura y reproducción de audio de tu aplicación. Los registros y los eventos de transcripción se envían a la salida de error estándar para evitar que alteren el flujo de audio.
Para Go, usa Go 1.26 o posterior, guarda el ejemplo como main.go, inicializa un módulo con go mod init live-demo e instala github.com/openai/openai-go/v3@v3.85.1 con go get. Para Java, usa Java 17 o posterior, agrega la dependencia de Maven com.openai:openai-java:4.95.0 y usa la clase LiveConnectionWebsocketExample. Para Ruby 3.3 o posterior, instala el SDK con gem install openai -v 0.110.0, instala su dependencia de WebSocket con gem install async-websocket y guarda el ejemplo como client.rb.
import OpenAI from "openai";
import { LiveWS } from "openai/resources/live/ws";
// stdin and stdout carry raw mono PCM16 audio at 24 kHz, not WAV files.
// Supply microphone bytes continuously and play stdout in the same format.
process.stdin.pause();
const ws = new LiveWS(new OpenAI());
let started = false;
let closing = false;
let finalized = false;
let pendingByte = Buffer.alloc(0);
let closeTimeout;
ws.socket.on("open", () => {
ws.send({
type: "session.start",
event_id: "event_start",
session: {
model: "gpt-live-1",
instructions:
"Be concise. Delegate requests needing current information to the backend, which can search the web.",
audio: {
format: { type: "audio/pcm", rate: 24000 },
output: { voice: "marin" },
},
delegation: {
type: "responses",
responses: {
model: "gpt-5.6-luna",
tools: [{ type: "web_search" }],
tool_choice: "auto",
},
},
},
});
});
process.stdin.on("data", (chunk) => {
if (!started || closing || ws.socket.readyState !== 1) return;
const bytes = Buffer.concat([pendingByte, chunk]);
const completeLength = bytes.length - (bytes.length % 2);
pendingByte = bytes.subarray(completeLength);
if (completeLength) {
ws.send({
type: "session.input_audio.append",
audio: bytes.subarray(0, completeLength).toString("base64"),
});
}
});
// Register the final-event handler before any close command can be sent.
ws.on("event", (event) => {
if (event.type === "session.started") {
started = true;
console.error("Session ready", event.session.id);
process.stdin.resume();
} else if (event.type === "session.output_audio.delta") {
process.stdout.write(Buffer.from(event.delta, "base64"));
} else if (event.type === "session.closed") {
finalized = true;
clearTimeout(closeTimeout);
process.stdin.pause();
console.error("Final session usage", event.usage);
ws.close();
} else {
// Includes transcript deltas and nested response.event usage.
console.error(JSON.stringify(event));
}
});
process.on("SIGINT", () => {
if (closing) return;
if (!started || ws.socket.readyState !== 1) {
ws.socket.platformSocket.terminate();
return;
}
closing = true;
process.stdin.pause();
ws.send({ type: "session.close" });
closeTimeout = setTimeout(() => {
console.error("Incomplete finalization: session.closed was not received");
process.exitCode = 1;
ws.socket.platformSocket.terminate();
}, 15_000);
});
ws.on("error", (error) => {
console.error(error.message);
process.exitCode = 1;
});
ws.socket.on("close", () => {
clearTimeout(closeTimeout);
process.stdin.pause();
if (!finalized) {
console.error("Connection closed without final session usage");
process.exitCode = 1;
}
});Ejecuta node client.mjs, python client.py, go run ., ruby client.rb o tu aplicación Java con la fuente de audio y el reproductor conectados. Cuando aparezca Session ready, envía un flujo continuo de audio del micrófono a la misma velocidad a la que se capturan las muestras. Enviar un archivo completo de una sola vez por una tubería no simula un micrófono en vivo. La indicación de fin de archivo (EOF) en la fuente de audio no termina la conversación. Envía SIGINT al proceso para solicitar un cierre ordenado.
El ejemplo conecta los flujos de audio. Tu aplicación se encarga de la captura, el almacenamiento en búfer, la reproducción y, cuando sea necesario, el remuestreo. Prueba estas funciones con tus dispositivos y tu red antes de evaluar el comportamiento del modelo.
Elegir el formato de audio
Configura session.audio.format al iniciar la sesión. La entrada y la salida usan el mismo formato, que no se puede cambiar durante la sesión.
{"type":"audio/pcm","rate":24000}: audio PCM mono de 16 bits con signo en orden little-endian a 24 kHz. Es el formato predeterminado.{"type":"audio/pcm","rate":16000}: audio PCM mono de 16 bits con signo en orden little-endian a 16 kHz.{"type":"audio/pcmu","rate":8000}: codificación G.711 con ley μ a 8 kHz, con un byte por muestra.{"type":"audio/pcma","rate":8000}: codificación G.711 con ley A a 8 kHz, con un byte por muestra.
Codifica los bytes sin procesar en base64, sin incluir un encabezado WAV ni de otro contenedor. Cada bloque PCM debe contener muestras completas de 16 bits, por lo que su longitud en bytes debe ser par. Si sobra un byte al final de un bloque de entrada, el ejemplo lo incorpora al siguiente. Fuera de esa condición, puedes dividir el audio en bloques donde quieras, siempre que el flujo sea continuo y conserve el orden.
Remuestrea el audio si su frecuencia de muestreo difiere de la configurada. Cambiar el formato en la configuración no convierte los bytes de entrada. Para adaptar el ejemplo a G.711, reenvía los bytes codificados de cada bloque sin aplicar la lógica de alineación en pares de bytes propia de PCM y configura el reproductor de salida para que use el mismo códec. Si el flujo G.711 coincide con el formato configurado, puedes transmitirlo sin convertirlo a PCM. Para conectar una llamada telefónica, consulta Integraciones de telefonía.
Enviar y recibir eventos
Envía cada evento como un mensaje de texto JSON. El audio se transmite en base64 dentro de esos mensajes.
- Enviar audio: envía
session.input_audio.appendcon los bytes sin procesar codificados en base64 en el campoaudio. Al agregar audio, no recibirás una confirmación. - Recibir audio: decodifica
deltade cada eventosession.output_audio.deltay coloca el audio en la cola para reproducirlo en orden con el formato configurado. - Recibir transcripciones: agrega el texto del campo
deltade los eventossession.input_transcript.deltaysession.output_transcript.deltaal final de la transcripción correspondiente. - Recibir eventos del backend: cuando uses la delegación a Responses, procesa el campo
eventanidado en cada mensajeresponse.event. - Manejar errores: usa los eventos
errorpara manejar los comandos rechazados y los errores de sesión. Si está presente, usaerror.client_event_idpara identificar el comando.
Usa la cola de audio de tu aplicación para seguir el avance de la reproducción. La conexión WebSocket principal de GPT-Live envía el audio de salida sin campos de tiempo ni un evento que indique el fin de ese audio. Usa las marcas de tiempo de la transcripción para organizar los subtítulos y los eventos del backend para seguir el trabajo delegado.
Mientras el audio se transmite de forma continua, GPT-Live decide cuándo escuchar y cuándo hablar. Usa response.create para iniciar o continuar el trabajo delegado al backend. Consulta Delegación y herramientas para conocer ese flujo de trabajo.
Configurar una sesión en curso
El modelo Live, las instrucciones iniciales de conversación, el formato de audio, la voz y el modo de delegación quedan fijos al iniciar la sesión. Usa session.update para cambiar los ajustes admitidos por el modo de delegación actual. Los ajustes que omitas conservarán sus valores. Si la actualización se completa correctamente, recibirás session.updated con la configuración efectiva de la sesión.
Usa session.instructions.append para agregar instrucciones de conversación y session.input_audio.mute o session.input_audio.unmute para controlar el audio entrante. Silenciar la entrada no cancela el trabajo del backend ni detiene la voz generada. Consulta Administración de sesiones para obtener más información sobre las actualizaciones de contexto, las transcripciones, los controles de entrada y el uso.
Cerrar la sesión
Cuando termine la conversación, envía session.close. Antes de enviarlo, registra el controlador de session.closed. Sigue recibiendo eventos hasta que llegue ese evento y luego libera la conexión. El ejemplo espera hasta 15 segundos e informa que el cierre quedó incompleto si no llega el evento final.
Conserva los datos finales de uso de voz de session.closed y los eventos de uso del backend que ya recibiste. Cada actualización de la duración de voz indica el total acumulado hasta ese momento. No sumes esos valores. Si se produce un error de transporte o se agota el tiempo de espera antes de recibir session.closed, el uso final queda sin confirmar. Consulta Administración de sesiones para conocer el ciclo de vida completo.
La API de WebSockets cuenta con amplio soporte para transferir datos en tiempo real y es una excelente opción para conectarte a la Realtime API de OpenAI en aplicaciones que se comunican de servidor a servidor. Para clientes móviles y de navegador, recomendamos conectarte mediante WebRTC.
En una integración entre servidores con Realtime, tu backend se conecta directamente a la Realtime API mediante WebSocket. Puedes usar una clave de API estándar para autenticar la conexión, ya que el token solo estará disponible en el servidor seguro de tu backend.
Conectarse mediante WebSocket
Los siguientes ejemplos muestran cómo conectarte a la Realtime API mediante WebSocket. Además de usar la URL de WebSocket que se muestra a continuación, debes enviar un encabezado de autenticación con tu clave de API de OpenAI. Si tu aplicación asigna identificadores de seguridad, envía en el encabezado OpenAI-Safety-Identifier un identificador estable que proteja la privacidad del usuario final y corresponda a ese usuario.
Puedes usar WebSocket en un navegador con un token de API efímero, como se muestra en la guía de conexión con WebRTC. Sin embargo, si te conectas desde un cliente como un navegador o una aplicación móvil, WebRTC suele ofrecer una solución más robusta.
Módulo ws (Node.js)
import WebSocket from "ws";
const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1";
const ws = new WebSocket(url, {
headers: {
Authorization: "Bearer " + process.env.OPENAI_API_KEY,
"OpenAI-Safety-Identifier": "hashed-user-id",
},
});
let connected = false;
ws.on("message", function incoming(message) {
const event = JSON.parse(message.toString());
if (event.type === "error") throw new Error(event.error.message);
if (event.type === "session.created") {
connected = true;
console.log(`Connected to the Realtime API: ${event.session.id}`);
ws.close(1000);
}
});
ws.on("close", () => {
if (!connected)
throw new Error("Connection closed before the session was created");
});# example requires websocket-client library:
# pip install websocket-client
import os
import json
import websocket
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1"
headers = [
"Authorization: Bearer " + OPENAI_API_KEY,
"OpenAI-Safety-Identifier: hashed-user-id",
]
session_created = False
def on_message(ws, message):
global session_created
data = json.loads(message)
if data["type"] == "session.created":
session_created = True
print("Connected to the Realtime API:", data["session"]["id"])
ws.close()
elif data["type"] == "error":
ws.close()
ws = websocket.WebSocketApp(
url,
header=headers,
on_message=on_message,
)
ws.run_forever()
if not session_created:
raise RuntimeError("Connection closed before the Realtime session was created.")Instala las gemas necesarias con
gem install openai async-websocket.
require "openai"
client = OpenAI::Client.new(
default_headers: { "OpenAI-Safety-Identifier" => "hashed-user-id" }
)
client.realtime.connect(model: "gpt-realtime-2.1") do |connection|
created = connection.find do |event|
raise event.error.message if event.is_a?(OpenAI::Realtime::RealtimeErrorEvent)
next unless event.is_a?(OpenAI::Realtime::SessionCreatedEvent)
puts("Connected to the Realtime API: #{event.session[:id]}")
true
end
raise "Connection closed before the session was created" unless created
endUsa Java 17 o posterior con com.openai:openai-java:4.75.1.
import com.openai.client.okhttp.OkHttpClient;
import com.openai.core.ClientOptions;
import com.openai.helpers.RealtimeConnection;
import com.openai.helpers.RealtimeWebSocketOptions;
import com.openai.models.realtime.*;
var http = OkHttpClient.builder().build();
var options =
ClientOptions.builder()
.fromEnv()
.httpClient(http)
.putHeader("OpenAI-Safety-Identifier", "hashed-user-id")
.build();
try (http;
var connection =
RealtimeConnection.connect(
options,
RealtimeWebSocketOptions.builder().model("gpt-realtime-2.1").build())) {
while (true) {
var event = connection.receive();
if (event.error().isPresent())
throw new IllegalStateException(event.error().orElseThrow().toString());
if (event.sessionCreated().isPresent()) {
System.out.println("Connected to server.");
System.out.println(event);
break;
}
}
}Usa Go 1.26 o posterior e instala el SDK con
go get github.com/openai/openai-go/v3@v3.85.1. El SDK
gestiona el transporte a través del socket. Tu aplicación se encarga de procesar los eventos,
capturar y reproducir el audio y restaurar el estado de la sesión después de una reconexión.
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
client := openai.NewClient()
conn, err := client.Realtime.Connect(ctx, realtime.RealtimeConnectionOptions{}, option.WithQuery("model", "gpt-realtime-2.1"), option.WithHeader("OpenAI-Safety-Identifier", "hashed-user-id"))
if err != nil {
return err
}
defer conn.Close()Instala el SDK con
dotnet add package OpenAI –version 2.14.0. La Realtime API
usa tipos experimentales del SDK. El ejemplo incluye la directiva necesaria
para gestionar la advertencia.
using OpenAI.Realtime;
#pragma warning disable OPENAI002
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
RealtimeClient client = new(key);
RealtimeSessionClientOptions options = new();
options.Headers["OpenAI-Safety-Identifier"] = "hashed-user-id";
using CancellationTokenSource timeout = new(TimeSpan.FromSeconds(30));
using RealtimeSessionClient session = await client.StartConversationSessionAsync("gpt-realtime-2.1", options, cancellationToken: timeout.Token);
await foreach (RealtimeServerUpdate update in session.ReceiveUpdatesAsync(timeout.Token))
{
if (update is RealtimeServerUpdateError error)
throw new InvalidOperationException(error.Error.Message);
if (update is RealtimeServerUpdateSessionCreated)
{
Console.WriteLine("Connected to server.");
Console.WriteLine(System.ClientModel.Primitives.ModelReaderWriter.Write(update));
return;
}
}
throw new InvalidOperationException("Connection closed before session creation.");/*
Note that in client-side environments like web browsers, we recommend
using WebRTC instead. It is possible, however, to use the standard
WebSocket interface in browser-like environments like Deno and
Cloudflare Workers.
*/
const ws = new WebSocket(
"wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1",
[
"realtime",
// Use a short-lived token fetched from your application server.
"openai-insecure-api-key." + OPENAI_REALTIME_EPHEMERAL_KEY,
]
);
ws.addEventListener("open", function open() {
console.log("Connected to server.");
});
ws.addEventListener("message", function incoming(event) {
console.log(event.data);
});Enviar y recibir eventos
Para gestionar una sesión de la Realtime API, se combinan los eventos del cliente, que envías desde tu aplicación, con los eventos del servidor, que genera la Realtime API para indicar qué ocurre durante el ciclo de vida de la sesión.
A través de la conexión WebSocket, envías y recibes eventos serializados en JSON como cadenas de texto. El siguiente ejemplo usa Node.js. Los mismos principios se aplican a otras bibliotecas de WebSocket.
import WebSocket from "ws";
const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1";
const ws = new WebSocket(url, {
headers: {
Authorization: "Bearer " + process.env.OPENAI_API_KEY,
"OpenAI-Safety-Identifier": "hashed-user-id",
},
});
ws.on("open", function open() {
console.log("Connected to server.");
// Send client events over the WebSocket once connected
ws.send(
JSON.stringify({
type: "session.update",
session: {
type: "realtime",
instructions: "Be extra nice today!",
},
})
);
});
// Listen for and parse server events
ws.on("message", function incoming(message) {
console.log(JSON.parse(message.toString()));
});La interfaz WebSocket es quizás la interfaz de más bajo nivel disponible para interactuar con un modelo Realtime. Al usarla, te encargas tanto de enviar como de procesar los bloques de audio codificados en Base64 que se transmiten a través del socket.
Para aprender a enviar y recibir audio mediante WebSockets, consulta la guía de conversaciones con Realtime.