Elige la API para ver los pasos de conexión y los eventos de sesión correspondientes.
Conecta las llamadas telefónicas entrantes y salientes a GPT-Live mediante una troncal SIP. Tu proveedor intercambia el audio de las llamadas con OpenAI, mientras que tu backend gestiona la configuración de la sesión, los controles de llamada y la lógica de negocio. La señalización SIP usa TLS y GPT-Live requiere SRTP para el audio de las llamadas.
- Gestionar una llamada entrante: recibe un webhook de llamada entrante y luego acepta o rechaza la llamada.
- Hacer una llamada saliente: crea una sesión para marcar un número telefónico a través de tu proveedor. No necesitas un webhook de llamada entrante ni una solicitud de aceptación.
Usa una conexión de banda lateral cuando tu backend necesite recibir eventos de sesión o enviar comandos. Esta conexión se vincula a la conversación existente mientras SIP transporta el audio. Asigna un solo controlador a cada acción para evitar que las herramientas se ejecuten dos veces si se duplica la entrega de un webhook o si varias conexiones reciben el mismo evento.
Gestionar una llamada entrante
Dirige las llamadas telefónicas entrantes de tu proveedor SIP a tu proyecto de OpenAI. Tu backend recibe un webhook y decide si acepta cada llamada.
Configurar el número telefónico y la troncal
Usa un proveedor de troncales SIP, como Twilio, para conectar un número telefónico a GPT-Live. Después de comprarle un número a tu proveedor, sigue estos pasos:
- Abre tu proyecto en la configuración de OpenAI. En Webhooks, crea un punto de acceso de webhooks y suscríbelo al evento
live.transport.incoming. - Busca el ID de tu proyecto en General. Comienza con
proj_. Usa el ID del proyecto al que pertenece el webhook. - Dirige la troncal SIP de tu proveedor al URI SIP global,
sip:$PROJECT_ID@sip.api.openai.com;transport=tls, o usa uno de estos puntos de acceso regionales:- Para la residencia de datos en Europa, usa
sip:$PROJECT_ID@sip-eu.api.openai.com;transport=tls. - Para usar hosts SIP ubicados físicamente en la India, usa
sip:$PROJECT_ID@sip-in.api.openai.com;transport=tls.
- Para la residencia de datos en Europa, usa
Antes de seguir estos pasos, confirma que tu proyecto tenga habilitada la compatibilidad con SIP de GPT-Live y que la troncal SIP de tu proveedor dirija las llamadas a ese proyecto.
Recibir la llamada entrante
Cuando OpenAI recibe una llamada para tu proyecto, envía un evento live.transport.incoming a tu punto de acceso de webhooks. Verifica la firma del webhook y descarta las entregas duplicadas. Luego, acepta o rechaza la llamada.
El webhook identifica la llamada SIP mediante data.type: "sip" y proporciona data.session_id. Usa ese ID de sesión sin modificarlo en todas las acciones de control de llamadas de Live. Trata data.sip_headers como metadatos no confiables de quien llama. No los uses para autorizar la llamada.
Este es un ejemplo del cuerpo del webhook:
{
"object": "event",
"id": "evt_abc123",
"type": "live.transport.incoming",
"created_at": 1750287018,
"data": {
"type": "sip",
"session_id": "live_123",
"sip_headers": [
{ "name": "From", "value": "sip:+14155550123@sip.example.com" },
{ "name": "To", "value": "sip:+18005550100@sip.example.com" },
{ "name": "Call-ID", "value": "call-123@example.com" }
]
}
}El campo created_at contiene una marca de tiempo Unix en segundos. Los encabezados de entrega incluyen webhook-id para identificar entregas duplicadas, webhook-timestamp para indicar cuándo se intentó la entrega y webhook-signature para verificar la firma. Consulta los ejemplos de verificación de webhooks para ver cómo implementar la verificación en los controladores del servidor.
Las integraciones existentes aún pueden recibir el evento obsoleto live.call.incoming, que no incluye data.type. Durante la migración, procesa ambos nombres de evento y conserva la suscripción anterior hasta que terminen todas las entregas y los reintentos pendientes de esa suscripción. La misma llamada pendiente también puede generar un webhook de Realtime. Asigna a un solo controlador la decisión de aceptar o rechazar la llamada para evitar aceptarla mediante ambas API.
Aceptar o rechazar la llamada
Aplica las reglas de autorización y enrutamiento de tu aplicación. Para aceptar la llamada, envía una solicitud autenticada POST /v1/live/sessions/{session_id}/accept con un objeto session en el nivel superior:
{
"session": {
"type": "live",
"model": "gpt-live-1",
"instructions": "You are answering an inbound support call.",
"audio": { "output": { "voice": "marin" } },
"delegation": { "type": "client" }
}
}Usa Authorization: Bearer $OPENAI_API_KEY en las solicitudes de control de llamadas que envíes desde tu backend de confianza. Elige la voz y el modo de delegación al aceptar la llamada. SIP negocia el formato de audio, así que omite audio.format. El ejemplo selecciona la delegación al cliente, por lo que tu backend debe encargarse del trabajo delegado. Consulta Delegación y herramientas para ver las configuraciones del cliente y de Responses.
Si la llamada se acepta correctamente, la solicitud devuelve 200 OK con el cuerpo vacío después de que se inicializa la sesión. Gestiona los errores HTTP antes de dar la llamada por aceptada.
Para rechazar la llamada, envía POST /v1/live/sessions/{session_id}/reject con un código de estado SIP, como { "status_code": 486 } para indicar que la línea está ocupada. El código de estado debe ser un entero entre 300 y 699, ambos inclusive. Prevalece la primera decisión de aceptar o rechazar la llamada. Si después se intenta tomar otra decisión sobre la misma llamada, la solicitud devuelve decision_already_made.
Conectar tu backend
Después de aceptar la llamada, abre una conexión WebSocket de banda lateral en wss://api.openai.com/v1/live/sessions/{session_id}/attach. Usa el ID de la sesión aceptada, la misma autenticación del proyecto y los mismos encabezados de conexión. No vuelvas a enviar session.start.
SIP transporta el audio de la llamada. Usa la conexión de banda lateral para las transcripciones, la delegación, las herramientas, los comandos y el audio reflejado. Asigna un único responsable a cada efecto secundario, incluso si varias conexiones reciben el mismo evento.
Una vez establecida la conexión, usa los controles de la llamada activa para enviar tonos del teclado telefónico, transferir la llamada o colgar.
Hacer una llamada saliente
Llama a un número telefónico a través de tu proveedor SIP con Crear sesión. Tu proveedor gestiona la conexión con la red telefónica mientras GPT-Live mantiene la conversación.
Todas las organizaciones pueden hacer llamadas SIP salientes mediante la API de Live. El punto de acceso de la Realtime API para crear llamadas no admite esta función.
Configurar la troncal
Usa una troncal que admita señalización TLS y transmisión de medios con SDES-SRTP. Habilita SRTP en la configuración de tu proveedor antes de hacer una llamada.
Incluye la configuración de la troncal en cada solicitud:
| Campo | Valor |
|---|---|
transport.destination |
El número telefónico al que quieres llamar, en formato E.164, por ejemplo, +14155550123. No se admiten URI SIP como destino. |
transport.trunk.provider_url |
Un punto de acceso del proveedor, como sips:sip.example.com:5061. El puerto predeterminado es 5061. El parámetro ;transport=tcp es opcional. |
transport.trunk.auth.type |
digest para la autenticación SIP Digest. |
transport.trunk.auth.username |
Tu nombre de usuario SIP asignado por el proveedor. |
transport.trunk.auth.password |
Tu contraseña SIP del proveedor. |
transport.trunk.caller_number |
El número telefónico de origen que se envía a tu proveedor, en formato E.164. |
El punto de acceso del proveedor debe usar sips: para la señalización TLS. No incluyas credenciales, rutas, encabezados de URI ni otros parámetros de URI en la URL. Se rechazan los nombres de host locales y las direcciones IP privadas o locales escritas de forma literal. Guarda tu clave de API de OpenAI y tus credenciales SIP en tu servidor.
Crear la sesión
Envía POST /v1/live/sessions con la configuración de tu sesión y transport.type: "sip". Elige la voz y el modo de delegación al crear la sesión. Omite audio.format porque SIP negocia el formato de audio.
Este ejemplo usa curl y jq. Define OPENAI_API_KEY, SIP_USERNAME y SIP_PASSWORD en el entorno de tu servidor y sustituye el punto de acceso del proveedor y los números telefónicos del ejemplo por tus propios valores. El ejemplo selecciona la delegación al cliente, por lo que tu backend debe encargarse del trabajo delegado.
jq -n \
--arg username "$SIP_USERNAME" \
--arg password "$SIP_PASSWORD" \
'{
"session": {
"model": "gpt-live-1",
"instructions": "Help the user schedule an appointment.",
"audio": { "output": { "voice": "marin" } },
"delegation": { "type": "client" }
},
"transport": {
"type": "sip",
"destination": "+14155550123",
"trunk": {
"provider_url": "sips:sip.example.com:5061",
"auth": {
"type": "digest",
"username": $username,
"password": $password
},
"caller_number": "+14155550100"
}
}
}' | curl https://api.openai.com/v1/live/sessions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @-La solicitud devuelve 200 OK una vez que se inicializa la sesión:
{
"session": { "id": "live_123" },
"transport": { "type": "sip" }
}Esta respuesta no indica que alguien haya contestado la llamada. No contiene SDP ni credenciales de la troncal. Conserva session.id sin modificarlo para la conexión de banda lateral y los controles de llamada. Para una llamada saliente no necesitas un webhook de llamadas entrantes ni una solicitud de aceptación.
Monitorear y finalizar la llamada
Conecta tu backend a wss://api.openai.com/v1/live/sessions/{session_id}/attach con tu clave de API de OpenAI. No vuelvas a enviar session.start. La conexión de banda lateral transmite los eventos de la conversación, el trabajo delegado y las actualizaciones sobre el progreso de la llamada mientras SIP transporta el audio.
| Evento | Significado |
|---|---|
transport.ringing |
El proveedor indica que el teléfono está sonando o que ya se transmiten medios antes de que se conteste la llamada. |
transport.answered |
Se contestó la llamada y se estableció la transmisión de medios. |
transport.failed |
No se pudo establecer la llamada después de inicializar la sesión. Revisa error.code y error.message. |
Cada evento de progreso de la llamada incluye event_id y session_id. Conecta tu backend en cuanto se cree la sesión. La conexión de banda lateral solo retransmite los eventos de los últimos 3 segundos, por lo que, si te conectas más tarde, puedes perder eventos anteriores de la llamada. Los eventos retransmitidos conservan sus ID originales. Usa event_id para descartar eventos duplicados.
Una vez establecida la conexión, usa los controles de la llamada activa para enviar tonos del teclado telefónico, transferir la llamada o colgar. Mantén abierta la conexión de banda lateral para recibir session.closed y los datos finales de uso, tal como se describe en Uso y cierre ordenado.
Gestionar límites y errores
El teléfono puede sonar hasta 3 minutos y, una vez conectada, la llamada puede durar hasta 2 horas. Estos límites no se pueden configurar en la solicitud de creación.
Si la configuración de la sesión no es válida, el error se devuelve en la respuesta a la solicitud de creación. Si falla el establecimiento del transporte, la solicitud puede devolver 502. Si se agota el tiempo de espera de inicialización, devuelve 504. Una vez creada la sesión, monitorea transport.failed para detectar fallas asíncronas al establecer la llamada.
Gestionar una llamada activa
Estos controles se aplican tanto a las llamadas SIP entrantes como a las salientes.
Enviar y recibir eventos del teclado telefónico
La conexión de banda lateral recibe transport.dtmf.received cuando quien llama presiona una tecla. Para enviar un tono DTMF a la troncal SIP, envía un evento de cliente transport.dtmf.send mediante el WebSocket de banda lateral. Una vez que el tono se envía correctamente, la conexión de banda lateral recibe transport.dtmf.sent.
Si proporcionas un event_id, la notificación lo incluye como client_event_id. Si ocurre un error, se devuelve un evento error con error.client_event_id.
Transferir o finalizar la llamada
Para transferir la llamada, envía POST /v1/live/sessions/{session_id}/refer con { "target_uri": "sip:agent@example.com" } para indicar el destino. Para colgar, envía POST /v1/live/sessions/{session_id}/hangup sin cuerpo en la solicitud. Ambas solicitudes devuelven 200 OK con el cuerpo vacío si se completan correctamente.
El destino de la transferencia se usa como valor del encabezado SIP Refer-To. Puede ser un URI telefónico, como tel:+14155550123, o un URI SIP, como sip:agent@example.com. Tu proveedor se encarga del resto de la transferencia.
Mantén abierta la conexión de banda lateral hasta que session.closed proporcione los datos finales de uso. Consulta Uso y cierre ordenado para saber cómo se informa el uso y conocer los motivos de cierre.
Requisitos de red para SIP
Las llamadas SIP de GPT-Live usan rutas de red distintas para la señalización y los medios. Configura tu red para permitir ambos tipos de tráfico:
- Señalización SIP:
sip.api.openai.comysip-eu.api.openai.comson puntos de acceso con enrutamiento basado en GeoIP. El punto de acceso de la India,sip-in.api.openai.com, dirige el tráfico a hosts SIP ubicados en ese país. Permite el tráfico TCP/TLS saliente hacia el puerto5061de las direcciones que devuelve el DNS para el punto de acceso que elegiste. - Medios SRTP: en el SDP negociado, la API especifica una dirección IP independiente para los medios y un puerto UDP. Permite el tráfico SRTP por UDP en ambas direcciones entre tu red y los siguientes bloques CIDR:
13.79.45.80/2820.204.17.112/2823.98.140.64/2840.67.149.176/2840.83.204.240/28
Próximos pasos con GPT-Live
- Guía de prompts: escribe instrucciones para tu agente de voz.
- Webhooks y controles del lado del servidor: gestiona una sesión desde tu backend.
- Delegación y herramientas: conecta la voz con tu backend de razonamiento y herramientas.
- Gestionar sesiones: gestiona las transcripciones, el estado de la sesión y su cierre.
- Latencia y costo: conoce cómo funcionan la latencia y el uso.
- Integraciones de GPT-Live con socios: encuentra guías de configuración y ejemplos para cada proveedor.
SIP es un protocolo que se usa para hacer llamadas telefónicas por internet. Con SIP y la Realtime API puedes dirigir las llamadas telefónicas entrantes a la API.
Descripción general
Para conectar un número telefónico a la Realtime API, usa un proveedor de troncales SIP, como Twilio. Este servicio convierte tu llamada telefónica en tráfico IP. Una vez que compres un número telefónico a tu proveedor de troncales SIP, sigue estos pasos.
Primero, crea un webhook para las llamadas entrantes. En platform.openai.com, ve a Configuración > Proyecto > Webhooks.
Luego, dirige tu troncal SIP al URI SIP global de OpenAI, sip:$PROJECT_ID@sip.api.openai.com;transport=tls, con el ID del proyecto en el que configuraste el webhook. Para el enrutamiento regional, usa uno de estos puntos de acceso:
- Para la residencia de datos en Europa, usa
sip:$PROJECT_ID@sip-eu.api.openai.com;transport=tls. - Para usar hosts SIP ubicados físicamente en la India, usa
sip:$PROJECT_ID@sip-in.api.openai.com;transport=tls.
Para encontrar tu $PROJECT_ID, ve a Configuración > Proyecto > General. En esa página verás el ID del proyecto, que comienza con proj_.
Cuando OpenAI reciba tráfico SIP asociado a tu proyecto, enviará a tu webhook un evento realtime.call.incoming como el del siguiente ejemplo:
POST https://my_website.com/webhook_endpoint
user-agent: OpenAI/1.0 (+https://platform.openai.com/docs/webhooks)
content-type: application/json
webhook-id: wh_685342e6c53c8190a1be43f081506c52 # unique id for idempotency
webhook-timestamp: 1750287078 # timestamp of delivery attempt
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4= # signature to verify authenticity from OpenAI
{
"object": "event",
"id": "evt_685343a1381c819085d44c354e1b330e",
"type": "realtime.call.incoming",
"created_at": 1750287018, // Unix timestamp
"data": {
"call_id": "some_unique_id",
"sip_headers": [
{ "name": "From", "value": "sip:+142555512112@sip.example.com" },
{ "name": "To", "value": "sip:+18005551212@sip.example.com" },
{ "name": "Call-ID", "value": "03782086-4ce9-44bf-8b0d-4e303d2cc590"}
]
}
}Al recibir el webhook, puedes aceptar o rechazar la llamada con el valor de call_id que incluye. Al aceptar la llamada, proporciona la configuración necesaria para la sesión de la Realtime API, como las instrucciones y la voz. Una vez establecida la sesión, puedes abrir una conexión WebSocket y monitorearla como de costumbre. A continuación se describen las API para aceptar, rechazar, monitorear, transferir y colgar la llamada.
Aceptar la llamada
Usa el punto de acceso para aceptar llamadas para aprobar la llamada entrante y configurar la sesión en tiempo real que la atenderá. Envía los mismos parámetros que usarías en una solicitud de create client secret. Asegúrate de configurar el modelo en tiempo real, la voz, las herramientas o las instrucciones antes de conectar la llamada al modelo.
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/accept" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "realtime",
"model": "gpt-realtime-2.1",
"instructions": "You are Alex, a friendly concierge for Example Corp."
}'La ruta de la solicitud debe incluir el call_id del webhook realtime.call.incoming. Todas las solicitudes requieren el encabezado Authorization que se muestra arriba. El punto de acceso devuelve 200 OK cuando el tramo SIP de la llamada ya está en fase de timbrado y se está estableciendo la sesión en tiempo real.
Rechazar la llamada
Usa el punto de acceso para rechazar llamadas si no quieres atender una llamada entrante, por ejemplo, si el número tiene un código de país no admitido. Proporciona el parámetro de ruta call_id y, si lo deseas, incluye el código de estado SIP status_code (por ejemplo, 486 para indicar “ocupado”) en el cuerpo JSON para controlar la respuesta que se envía al operador telefónico.
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/reject" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status_code": 486}'Si no proporcionas un código de estado, la API usa 603 Decline de forma predeterminada. Si la solicitud se completa correctamente, devuelve 200 OK después de que OpenAI entrega la respuesta SIP.
Monitorear los eventos de la llamada
Después de aceptar una llamada, abre una conexión WebSocket con la misma sesión para recibir eventos de forma continua y enviar comandos en tiempo real. Cuando te conectas a una llamada existente mediante el parámetro call_id, el argumento model no se usa porque el modelo ya se configuró mediante el punto de acceso accept.
Solicitud WebSocket
GET wss://api.openai.com/v1/realtime?call_id={call_id}
Parámetros de consulta
| Parámetro | Tipo | Descripción |
|---|---|---|
call_id |
cadena | Identificador de la llamada que proporciona el webhook realtime.call.incoming. |
Encabezados
Authorization: Bearer YOUR_API_KEY
El WebSocket funciona igual que cualquier otra conexión a la Realtime API. Envía response.create y otros eventos de cliente para controlar la llamada, y escucha los eventos del servidor para seguir su progreso. Consulta Webhooks y controles del lado del servidor para obtener más información.
import WebSocket from "ws";
const callId = "rtc_u1_9c6574da8b8a41a18da9308f4ad974ce";
const ws = new WebSocket(`wss://api.openai.com/v1/realtime?call_id=${callId}`, {
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
},
});
ws.on("open", () => {
ws.send(
JSON.stringify({
type: "response.create",
})
);
});Redirigir la llamada
Transfiere una llamada activa mediante el punto de acceso para transferir llamadas. Proporciona el call_id y el target_uri que se debe incluir en el encabezado SIP Refer-To (por ejemplo, tel:+14155550123 o sip:agent@example.com).
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/refer" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target_uri": "tel:+14155550123"}'OpenAI devuelve 200 OK una vez que reenvía la solicitud REFER a tu proveedor SIP. El sistema de destino se encarga del resto de la llamada para quien llama.
Colgar la llamada
Finaliza la sesión con el punto de acceso para colgar llamadas cuando tu aplicación deba desconectar a quien llama. Puedes usar este punto de acceso para finalizar sesiones en tiempo real tanto de SIP como de WebRTC.
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/hangup" \
-H "Authorization: Bearer $OPENAI_API_KEY"La API responde con 200 OK cuando empieza a desconectar la llamada.
Rangos de direcciones IP para señalización SIP y medios
Las llamadas SIP de Realtime usan rutas de red distintas para la señalización y los medios. Para que las llamadas funcionen correctamente, configura tu red para permitir ambos tipos de tráfico como se describe a continuación.
Señalización SIP
sip.api.openai.com y sip-eu.api.openai.com son puntos de acceso con enrutamiento basado en GeoIP. El punto de acceso de la India, sip-in.api.openai.com, dirige el tráfico a hosts SIP ubicados en ese país. Tu red debe permitir el tráfico TCP/TLS saliente hacia el puerto 5061 de las direcciones que devuelve el DNS para el punto de acceso que elegiste.
Medios SRTP
En el SDP negociado, la API especifica una dirección IP independiente para los medios y un puerto UDP. Tu red debe permitir el tráfico SRTP por UDP en ambas direcciones entre tu red y los siguientes bloques CIDR:
13.79.45.80/2820.204.17.112/2823.98.140.64/2840.67.149.176/2840.83.204.240/28
Ejemplos de servidor
El siguiente ejemplo muestra un controlador de realtime.call.incoming. Acepta la llamada y luego registra todos los eventos de la Realtime API.
Para el ejemplo de Ruby, define las variables de entorno OPENAI_API_KEY y OPENAI_WEBHOOK_SECRET. Luego instala las dependencias necesarias con gem install openai webrick async-websocket.
from flask import Flask, request, Response, jsonify, make_response
from openai import OpenAI, InvalidWebhookSignatureError
import asyncio
import json
import os
import requests
import time
import threading
import websockets
app = Flask(__name__)
client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
AUTH_HEADER = {"Authorization": "Bearer " + os.environ["OPENAI_API_KEY"]}
call_accept = {
"type": "realtime",
"instructions": "You are a support agent.",
"model": "gpt-realtime-2.1",
}
response_create = {
"type": "response.create",
"response": {
"instructions": ("Say to the user 'Thank you for calling, how can I help you'")
},
}
async def websocket_task(call_id):
try:
async with websockets.connect(
"wss://api.openai.com/v1/realtime?call_id=" + call_id,
additional_headers=AUTH_HEADER,
) as websocket:
await websocket.send(json.dumps(response_create))
while True:
response = await websocket.recv()
print(f"Received from WebSocket: {response}")
except Exception as e:
print(f"WebSocket error: {e}")
@app.route("/", methods=["POST"])
def webhook():
try:
event = client.webhooks.unwrap(request.data, request.headers)
except (InvalidWebhookSignatureError, ValueError) as e:
print("Invalid signature", e)
return Response("Invalid signature", status=400)
if event.type == "realtime.call.incoming":
requests.post(
"https://api.openai.com/v1/realtime/calls/"
+ event.data.call_id
+ "/accept",
headers={**AUTH_HEADER, "Content-Type": "application/json"},
json=call_accept,
).raise_for_status()
threading.Thread(
target=lambda: asyncio.run(websocket_task(event.data.call_id)),
daemon=True,
).start()
return Response(status=200)
if __name__ == "__main__":
app.run(port=8000)Próximos pasos
Ahora que te conectaste mediante SIP, usa el menú de navegación de la izquierda o abre estas páginas para empezar a desarrollar tu aplicación en tiempo real.
- Guía de prompts para Realtime
- Gestionar conversaciones
- Webhooks y controles del lado del servidor
- Gestionar costos
- Transcripción en tiempo real