Escolha a API para ver como estabelecer a conexão e quais eventos a sessão emite.
Conecte chamadas telefônicas de entrada e de saída ao GPT-Live por um tronco SIP. O provedor troca o áudio da chamada com a OpenAI, enquanto seu backend configura a sessão, controla a chamada e executa a lógica de negócio. A sinalização SIP usa TLS, e o GPT-Live exige SRTP para o áudio da chamada.
- Processar uma chamada recebida: receba o webhook de chamada recebida e, em seguida, aceite ou rejeite a chamada.
- Fazer uma chamada de saída: crie uma sessão para discar um número de telefone pelo seu provedor. Chamadas de saída dispensam o webhook de chamada recebida e a requisição para aceitar a chamada.
Use uma conexão auxiliar quando o backend precisar receber eventos da sessão ou enviar comandos. Essa conexão se vincula à conversa em andamento enquanto o SIP transporta o áudio. Atribua um único manipulador a cada ação para evitar que entregas duplicadas de webhooks ou eventos observados em mais de uma conexão acionem a mesma ferramenta duas vezes.
Processar uma chamada recebida
Encaminhe as chamadas recebidas pelo provedor SIP para seu projeto da OpenAI. O backend recebe um webhook e decide se aceita cada chamada.
Configurar o número de telefone e o tronco SIP
Use um provedor de tronco SIP, como a Twilio, para conectar um número de telefone ao GPT-Live. Depois de adquirir um número com o provedor, siga estas etapas:
- Abra seu projeto nas configurações da OpenAI. Em Webhooks, crie um endpoint de webhook e configure-o para receber o evento
live.transport.incoming. - Em Geral, localize o ID do projeto. Ele começa com
proj_. Use o projeto ao qual o webhook pertence. - Direcione o tronco SIP do provedor para a URI SIP global
sip:$PROJECT_ID@sip.api.openai.com;transport=tlsou use um dos seguintes endpoints regionais:- Para residência de dados na Europa, use
sip:$PROJECT_ID@sip-eu.api.openai.com;transport=tls. - Para hosts SIP localizados fisicamente na Índia, use
sip:$PROJECT_ID@sip-in.api.openai.com;transport=tls.
- Para residência de dados na Europa, use
Antes de usar este fluxo, confirme que o suporte a SIP do GPT-Live está habilitado no seu projeto e que o tronco SIP do provedor encaminha as chamadas para esse projeto.
Receber a chamada
Quando a OpenAI recebe uma chamada para seu projeto, ela envia um evento live.transport.incoming ao seu endpoint de webhook. Verifique a assinatura do webhook e elimine entregas duplicadas. Em seguida, aceite ou rejeite a chamada.
O webhook identifica uma chamada SIP com data.type: "sip" e fornece data.session_id. Use esse ID de sessão sem alterações em todas as ações de controle da chamada na API Live. Trate data.sip_headers como metadados não confiáveis fornecidos por quem liga. Não os use para autorizar a chamada.
Veja um exemplo do corpo do 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" }
]
}
}O campo created_at contém um timestamp Unix em segundos. Os cabeçalhos de entrega incluem webhook-id para identificar entregas duplicadas, webhook-timestamp para indicar o horário da tentativa de entrega e webhook-signature para verificar a assinatura. Consulte os exemplos de verificação de webhooks para implementar essa verificação nos manipuladores do servidor.
Integrações existentes ainda podem receber o evento obsoleto live.call.incoming, que não inclui data.type. Durante a migração, processe eventos com ambos os nomes e mantenha a assinatura antiga até que todas as entregas e novas tentativas do fluxo anterior tenham terminado. A mesma chamada pendente também pode gerar um webhook da Realtime API. Atribua a um único manipulador a decisão de aceitar ou rejeitar a chamada para evitar que as duas APIs a aceitem.
Aceitar ou rejeitar a chamada
Aplique as regras de autorização e roteamento do seu aplicativo. Para aceitar a chamada, envie uma requisição autenticada POST /v1/live/sessions/{session_id}/accept com um objeto session no nível superior:
{
"session": {
"type": "live",
"model": "gpt-live-1",
"instructions": "You are answering an inbound support call.",
"audio": { "output": { "voice": "marin" } },
"delegation": { "type": "client" }
}
}Envie as requisições de controle da chamada a partir do seu backend confiável usando Authorization: Bearer $OPENAI_API_KEY. Escolha a voz e o modo de delegação ao aceitar a chamada. O SIP negocia o formato de áudio, portanto omita audio.format. O exemplo seleciona a delegação ao cliente, o que exige que seu backend execute as tarefas delegadas. Consulte Delegação e ferramentas para ver as configurações de delegação ao cliente e à API Responses.
Quando a chamada é aceita, a API retorna 200 OK com o corpo vazio após inicializar a sessão. Trate os erros HTTP antes de considerar a chamada aceita.
Para rejeitar a chamada, envie POST /v1/live/sessions/{session_id}/reject com um código de status SIP, como { "status_code": 486 } para indicar que a linha está ocupada. O código deve ser um número inteiro entre 300 e 699, inclusive. A primeira decisão de aceitar ou rejeitar prevalece. Qualquer tentativa posterior de decidir sobre a mesma chamada retorna decision_already_made.
Conectar o backend à sessão
Depois de aceitar a chamada, abra um WebSocket auxiliar em wss://api.openai.com/v1/live/sessions/{session_id}/attach. Use o ID da sessão aceita, a mesma autenticação do projeto e os mesmos cabeçalhos de conexão. Não envie session.start novamente.
O SIP transporta o áudio da chamada. Use a conexão auxiliar para transcrições, delegação, ferramentas, comandos e áudio espelhado. Defina um único responsável por cada efeito colateral, mesmo que várias conexões recebam o mesmo evento.
Depois de estabelecer a conexão, use os controles da chamada ativa para enviar tons do teclado telefônico, transferir a chamada ou desligar.
Fazer uma chamada de saída
Ligue para um número de telefone pelo seu provedor SIP usando a operação Criar sessão. O provedor estabelece a conexão com a rede telefônica enquanto o GPT-Live conduz a conversa.
Todas as organizações podem fazer chamadas SIP de saída pela API Live. O endpoint de criação de chamadas da Realtime API não oferece esse recurso.
Configurar o tronco SIP
Use um tronco que aceite sinalização TLS e mídia SDES-SRTP. Habilite o SRTP nas configurações do provedor antes de fazer uma chamada.
Inclua a configuração do tronco em cada requisição:
| Campo | Valor |
|---|---|
transport.destination |
Número de telefone de destino no formato E.164, como +14155550123. Não há suporte a destinos especificados por URI SIP. |
transport.trunk.provider_url |
Endpoint do provedor, como sips:sip.example.com:5061. A porta padrão é 5061, e ;transport=tcp é opcional. |
transport.trunk.auth.type |
digest para autenticação SIP Digest. |
transport.trunk.auth.username |
Nome de usuário SIP fornecido pelo provedor. |
transport.trunk.auth.password |
Senha SIP fornecida pelo provedor. |
transport.trunk.caller_number |
Número de telefone de origem a ser enviado ao provedor, no formato E.164. |
O endpoint do provedor deve usar sips: para a sinalização TLS. Não inclua credenciais, caminhos, cabeçalhos de URI nem outros parâmetros de URI na URL. A API rejeita nomes de host locais e endereços IP privados ou locais fornecidos diretamente. Mantenha a chave de API da OpenAI e as credenciais SIP no servidor.
Criar a sessão
Envie POST /v1/live/sessions com a configuração da sessão e transport.type: "sip". Escolha a voz e o modo de delegação ao criar a sessão. Omita audio.format, pois o SIP negocia o formato de áudio.
Este exemplo usa curl e jq. Defina OPENAI_API_KEY, SIP_USERNAME e SIP_PASSWORD no ambiente do servidor e substitua o endpoint do provedor e os números de telefone do exemplo pelos seus. O exemplo seleciona a delegação ao cliente, o que exige que seu backend execute as tarefas delegadas.
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 @-A API retorna 200 OK após inicializar a sessão:
{
"session": { "id": "live_123" },
"transport": { "type": "sip" }
}Essa resposta não indica que alguém atendeu à chamada. Ela não contém SDP nem credenciais do tronco. Use session.id sem alterações na conexão auxiliar e nas operações de controle da chamada. Chamadas de saída dispensam o webhook de chamada recebida e a requisição para aceitar a chamada.
Monitorar e encerrar a chamada
Conecte o backend a wss://api.openai.com/v1/live/sessions/{session_id}/attach usando sua chave de API da OpenAI. Não envie session.start novamente. A conexão auxiliar transmite eventos da conversa, tarefas delegadas e informações sobre o andamento da chamada enquanto o SIP transporta o áudio.
| Evento | Significado |
|---|---|
transport.ringing |
O provedor informa que o telefone está tocando ou que há mídia antes do atendimento. |
transport.answered |
A chamada foi atendida e o fluxo de mídia foi estabelecido. |
transport.failed |
Falha ao estabelecer a chamada após a inicialização da sessão. Verifique error.code e error.message. |
Cada evento de andamento da chamada inclui event_id e session_id. Abra a conexão auxiliar imediatamente após criar a sessão. Ela só retransmite eventos dos 3 segundos anteriores. Se você se conectar mais tarde, poderá perder os primeiros eventos da chamada. Os eventos retransmitidos mantêm os IDs originais. Use event_id para eliminar duplicatas.
Depois de estabelecer a conexão, use os controles da chamada ativa para enviar tons do teclado telefônico, transferir a chamada ou desligar. Mantenha a conexão auxiliar aberta para receber session.closed e os dados finais de uso, conforme descrito em Uso e encerramento ordenado.
Lidar com limites e erros
O telefone pode tocar por até 3 minutos, e a chamada pode durar até 2 horas após a conexão. A requisição de criação não permite configurar esses limites.
Se a configuração da sessão for inválida, a API informará o erro na resposta à requisição de criação. Falhas ao configurar o transporte podem retornar 502. Se a inicialização exceder o tempo limite, a API retornará 504. Após criar a sessão, monitore transport.failed para detectar falhas assíncronas ao estabelecer a chamada.
Gerenciar uma chamada ativa
Esses controles se aplicam tanto às chamadas SIP de entrada quanto às de saída.
Enviar e receber eventos do teclado telefônico
A conexão auxiliar recebe transport.dtmf.received quando quem liga pressiona uma tecla. Para enviar um tom DTMF ao tronco SIP, envie um evento de cliente transport.dtmf.send pelo WebSocket auxiliar. Após o envio bem-sucedido do tom, a conexão auxiliar recebe transport.dtmf.sent.
Se você fornecer um event_id, a notificação incluirá esse valor como client_event_id. Em caso de falha, a API retornará um evento error com error.client_event_id.
Transferir ou encerrar a chamada
Para transferir a chamada, envie POST /v1/live/sessions/{session_id}/refer com { "target_uri": "sip:agent@example.com" }, especificando o destino desejado. Para desligar, envie POST /v1/live/sessions/{session_id}/hangup sem corpo na requisição. Em caso de sucesso, ambas as operações retornam 200 OK com o corpo vazio.
O destino da transferência é o valor do cabeçalho SIP Refer-To. Ele pode ser uma URI de telefone, como tel:+14155550123, ou uma URI SIP, como sip:agent@example.com. O provedor cuida das etapas restantes da transferência.
Mantenha a conexão auxiliar aberta até que session.closed forneça os dados finais de uso. Consulte Uso e encerramento ordenado para saber como a API informa o uso e os motivos de encerramento.
Requisitos de rede para SIP
As chamadas SIP do GPT-Live usam caminhos de rede separados para sinalização e mídia. Configure a rede para permitir os dois tipos de tráfego:
- Sinalização SIP:
sip.api.openai.comesip-eu.api.openai.comsão endpoints com roteamento por GeoIP. O endpoint da Índia,sip-in.api.openai.com, encaminha o tráfego para hosts SIP na Índia. Permita tráfego TCP/TLS de saída na porta5061para os endereços que o DNS retornar para o endpoint escolhido. - Mídia SRTP: No SDP negociado, a API especifica um endereço IP separado para mídia e uma porta UDP. Permita tráfego SRTP via UDP nos dois sentidos entre sua rede e os seguintes blocos CIDR:
13.79.45.80/2820.204.17.112/2823.98.140.64/2840.67.149.176/2840.83.204.240/28
Próximos passos com o GPT-Live
- Guia de prompts: escreva instruções para seu agente de voz.
- Webhooks e controles no servidor: gerencie uma sessão pelo backend.
- Delegação e ferramentas: conecte a interação por voz ao backend que executa o raciocínio e as ferramentas.
- Gerenciar sessões: gerencie as transcrições, o estado e o encerramento da sessão.
- Latência e custo: entenda a latência e o uso.
- Integrações de parceiros do GPT-Live: encontre guias de configuração e exemplos específicos para cada provedor.
O SIP é um protocolo usado para fazer chamadas telefônicas pela internet. Com o SIP e a Realtime API, você pode encaminhar chamadas recebidas diretamente para a API.
Visão geral
Para conectar um número de telefone à Realtime API, use um provedor de tronco SIP, como a Twilio. Esse serviço converte a chamada telefônica em tráfego IP. Depois de adquirir um número com o provedor, siga as instruções abaixo.
Primeiro, crie um webhook para chamadas recebidas. Em platform.openai.com, acesse Configurações > Projeto > Webhooks.
Em seguida, direcione o tronco SIP para a URI SIP global da OpenAI, sip:$PROJECT_ID@sip.api.openai.com;transport=tls, usando o ID do projeto em que você configurou o webhook. Para roteamento regional, use um dos seguintes endpoints:
- Para residência de dados na Europa, use
sip:$PROJECT_ID@sip-eu.api.openai.com;transport=tls. - Para hosts SIP localizados fisicamente na Índia, use
sip:$PROJECT_ID@sip-in.api.openai.com;transport=tls.
Para encontrar o $PROJECT_ID, acesse Configurações > Projeto > Geral. A página exibe o ID do projeto, que começa com proj_.
Quando a OpenAI receber tráfego SIP associado ao projeto, ela acionará seu webhook com um evento realtime.call.incoming, como no exemplo abaixo:
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"}
]
}
}Use o valor de call_id recebido no webhook para aceitar ou rejeitar a chamada. Ao aceitar a chamada, forneça a configuração necessária para a sessão da Realtime API, como instruções e voz. Depois que a sessão for estabelecida, você poderá abrir um WebSocket e monitorá-la normalmente. As seções a seguir descrevem as APIs para aceitar, rejeitar, monitorar, transferir e encerrar a chamada.
Aceitar a chamada
Use o endpoint de aceitação de chamadas para aprovar a chamada recebida e configurar a sessão em tempo real que vai atendê-la. Envie os mesmos parâmetros de uma requisição create client secret. Antes de conectar a chamada ao modelo, configure os parâmetros aplicáveis, como modelo em tempo real, voz, ferramentas ou instruções.
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."
}'O caminho da requisição deve incluir o call_id do webhook realtime.call.incoming. Toda requisição exige o cabeçalho Authorization mostrado acima. O endpoint retorna 200 OK quando o trecho SIP da chamada entra na fase de toque e a sessão em tempo real começa a ser estabelecida.
Rejeitar a chamada
Use o endpoint de rejeição de chamadas para recusar um convite SIP quando não quiser atender à chamada, por exemplo, se ela vier de um país cujo código não é aceito. Informe o parâmetro de caminho call_id. No corpo JSON, você pode incluir o status_code SIP, como 486 para indicar “ocupado”, e assim definir a resposta enviada à operadora.
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}'Se você não informar um código de status, a API usará 603 Decline por padrão. Quando a requisição é bem-sucedida, a API retorna 200 OK depois que a OpenAI entrega a resposta SIP.
Monitorar eventos da chamada
Depois de aceitar a chamada, abra uma conexão WebSocket com a mesma sessão para receber o fluxo de eventos e enviar comandos em tempo real. Quando você se conecta a uma chamada existente com o parâmetro call_id, a API ignora o argumento model, pois o modelo já foi configurado pelo endpoint accept.
Requisição WebSocket
GET wss://api.openai.com/v1/realtime?call_id={call_id}
Parâmetros de consulta
| Parâmetro | Tipo | Descrição |
|---|---|---|
call_id |
string | Identificador fornecido pelo webhook realtime.call.incoming. |
Cabeçalhos
Authorization: Bearer YOUR_API_KEY
O WebSocket funciona exatamente como qualquer outra conexão com a Realtime API. Envie response.create e outros eventos de cliente para controlar a chamada. Para acompanhar o andamento, monitore os eventos do servidor. Saiba mais em Webhooks e controles no servidor.
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",
})
);
});Redirecionar a chamada
Transfira uma chamada ativa usando o endpoint de transferência de chamadas. Informe o call_id e o target_uri que deve constar no cabeçalho SIP Refer-To, por exemplo, tel:+14155550123 ou 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"}'A OpenAI retorna 200 OK assim que encaminha a mensagem REFER ao provedor SIP. A partir daí, o sistema que recebe a transferência conduz o restante da chamada para quem ligou.
Encerrar a chamada
Encerre a sessão com o endpoint de encerramento de chamadas quando seu aplicativo precisar desconectar quem ligou. Esse endpoint permite encerrar sessões em tempo real tanto de SIP quanto de WebRTC.
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/hangup" \
-H "Authorization: Bearer $OPENAI_API_KEY"A API responde com 200 OK quando começa a encerrar a chamada.
Faixas de IP para sinalização SIP e mídia
As chamadas SIP da Realtime API usam caminhos de rede separados para sinalização e mídia. Para que as chamadas funcionem corretamente, configure a rede para permitir os dois tipos de tráfego conforme descrito abaixo.
Sinalização SIP
sip.api.openai.com e sip-eu.api.openai.com são endpoints com roteamento por GeoIP. O endpoint da Índia, sip-in.api.openai.com, encaminha o tráfego para hosts SIP na Índia. Sua rede deve permitir tráfego TCP/TLS de saída na porta 5061 para os endereços que o DNS retornar para o endpoint escolhido.
Mídia SRTP
No SDP negociado, a API especifica um endereço IP separado para mídia e uma porta UDP. Sua rede deve permitir tráfego SRTP via UDP nos dois sentidos entre sua rede e os seguintes blocos CIDR:
13.79.45.80/2820.204.17.112/2823.98.140.64/2840.67.149.176/2840.83.204.240/28
Exemplos de servidor
O exemplo a seguir mostra um manipulador de realtime.call.incoming. Ele aceita a chamada e depois registra todos os eventos da Realtime API.
Para executar o exemplo em Ruby, defina as variáveis de ambiente OPENAI_API_KEY e OPENAI_WEBHOOK_SECRET. Em seguida, instale as dependências necessárias com 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 passos
Com a conexão SIP estabelecida, use a navegação à esquerda ou acesse as páginas a seguir para começar a criar seu aplicativo em tempo real.
- Guia de prompts para a Realtime API
- Gerenciar conversas
- Webhooks e controles no servidor
- Gerenciar custos
- Transcrição em tempo real