选择您的应用使用的 API。每种 API 都有各自的身份验证、会话创建和事件规范。
选择电话连接方式
电话通话可以通过 SIP 中继或转发音频的应用接入 GPT-Live。请根据您现有的电话系统,以及应用需要在哪个环节处理音频,选择合适的连接方式。
| 连接 | 音频传输与应用职责 |
|---|---|
| SIP 直连 | 提供商与 OpenAI 交换通话音频。您的应用负责处理 Webhook、会话配置、通话决策和业务逻辑。 |
| 服务器音频桥接 | 您的应用通过 WebSocket 将提供商或房间的音频转发到 GPT-Live,并管理两端连接、事件转换、播放和通话生命周期。 |
提供商与您的应用之间的连接,以及您的应用与 OpenAI 之间的连接,彼此独立。例如,来电者可以通过 SIP 加入房间,而房间中的智能体则通过 WebSocket 连接到 GPT-Live。
正在使用 Twilio、Telnyx、LiveKit 或 Daily/Pipecat?请参阅 GPT-Live 合作伙伴集成,了解各提供商的专用指南。
SIP 直连
SIP 直连让通话音频始终通过提供商与 OpenAI 之间的媒体链路传输。SIP 信令使用 TLS,GPT-Live 要求通话音频使用 SRTP。您的后端仍负责来电决策、会话配置、授权和业务逻辑。
当您的后端需要接收会话事件或发送命令时,请使用旁路连接。它会接入现有对话,而音频仍由 SIP 传输。请为每项操作指定一个处理程序,避免因 Webhook 重复投递或多个连接观察到同一事件而导致工具重复执行。
请将 SIP 路由和提供商配置与使用它们的集成一同管理。Realtime Webhook 事件、通话标识符和接听请求载荷属于 Realtime API;Live 会话应使用 GPT-Live 规范。
处理通话生命周期
使用此流程前,请确认您的项目已启用 GPT-Live SIP 支持,并且提供商的 SIP 中继已路由到该项目。另一个选项卡中的 Realtime Webhook 和接听请求载荷遵循不同的 API 规范。
接收来电
为您的项目配置用于接收 live.transport.incoming 的 Webhook 端点。在决定如何处理通话之前,请验证 Webhook 签名并对投递进行去重。确认收到投递并不等于接听通话。
Webhook 通过 data.type: "sip" 标明这是 SIP 通话,并提供 data.session_id。每项 Live 通话操作都应原样使用该会话 ID。请将 data.sip_headers 视为不可信的来电者元数据,不能将其用作授权依据。
现有集成可能仍会收到已弃用的 live.call.incoming 事件,该事件不包含 data.type。迁移期间,请处理这两个事件名称,并保留旧订阅,直到旧事件的投递和重试全部完成。同一个待处理通话也可能触发 Realtime Webhook;请指定一个处理程序来决定接听或拒接,不要通过两个 API 同时接听。
接听或拒接通话
应用您的应用授权和路由规则。要接听通话,请发送经过身份验证的 POST /v1/live/sessions/{session_id}/accept 请求,并在请求中包含顶层 session 对象:
{
"session": {
"type": "live",
"model": "gpt-live-1",
"instructions": "You are answering an inbound support call.",
"audio": { "output": { "voice": "marin" } },
"delegation": { "type": "client" }
}
}请从可信后端发起通话控制请求,并使用 Authorization: Bearer $OPENAI_API_KEY。接听时请选择语音和委派模式。音频格式由 SIP 协商,因此请省略 audio.format。此示例选择客户端委派;您的后端必须处理委派的工作。有关客户端和 Responses 配置,请参阅委派与工具。
接听成功后,会在会话初始化完成时返回 200 OK,响应体为空。请先处理 HTTP 错误,再将通话视为已接听。
要拒接通话,请发送 POST /v1/live/sessions/{session_id}/reject,并附带 SIP 状态码,例如使用 { "status_code": 486 } 表示忙线。状态码必须是 300 至 699 之间的整数。首次接听或拒接决策生效;之后与之竞争的决策将返回 decision_already_made。
接入您的后端
接听后,请通过 wss://api.openai.com/v1/live/sessions/{session_id}/attach 建立旁路 WebSocket 连接。使用已接听通话的会话 ID,以及同一项目的身份验证信息和连接标头。不要再次发送 session.start。
SIP 负责传输通话音频。请使用旁路连接处理转录文本、委派、工具、命令和回传音频。即使多个连接观察到同一事件,也应为每项副作用指定唯一的执行方。
观察按键事件
当来电者按下按键时,旁路连接会收到 transport.dtmf.received;当托管工具成功发送音调后,旁路连接会收到 transport.dtmf.send。事件的 event 字段包含 0–9、*、# 或 A–D 中的一个值。
这些是供观察者接收的通知,而不是客户端命令。不要通过发送 transport.dtmf.send 来请求音调,也不要假定浏览器数据通道会接收按键事件。
转接或结束通话
要转接通话,请发送 POST /v1/live/sessions/{session_id}/refer,并使用 { "target_uri": "sip:agent@example.com" } 指定目的地。要挂断通话,请发送不带请求体的 POST /v1/live/sessions/{session_id}/hangup。两者成功时都会返回 200 OK,响应体为空。
释放应用资源之前,请保持旁路连接开启,以接收最终事件和用量信息。挂断请求成功或意外断开连接,都不能替代 session.closed。有关最终处理和关闭原因,请参阅用量与优雅关闭。
此流程用于接听来电。不支持通过 POST /v1/live/sessions 创建出站 SIP 通话;请使用相关的合作伙伴集成,由提供商负责呼出通话。
服务器音频桥接
当您的应用接收来自电话提供商或智能体框架的音频流时,请使用 GPT-Live WebSocket 连接。应用负责两端连接的身份验证、事件封装格式的转换,以及双向音频转发。
GPT-Live 支持通过 WebSocket 传输采样率为 8 kHz 的原始 G.711 μ-law 和 A-law 音频。当提供商的音频流使用相同的编解码器、采样率和声道数时,您的应用可以直接转发原始音频字节,无需将其转换为 PCM。请保持音频顺序,并使用每个连接要求的消息格式。音频格式相同并不意味着两种事件协议可以互换。
音频桥接还负责管理其排队等待播放的所有音频。设计应用时,请考虑提供商缓冲、中断和结束通话的处理。有关 Live 会话生命周期,请参阅管理会话;有关话轮切换和播放控制的变化,请参阅迁移到 GPT-Live。
请将提供商的通话或房间标识符与 OpenAI 会话 ID 一同保存,以便跨两个系统追踪同一段对话。
GPT-Live 后续步骤
- WebSockets:将服务器音频流连接到 GPT-Live。
- Webhook 与服务器端控制:从您的后端管理会话。
- 委派与工具:将语音连接到您的推理和工具后端。
- 管理会话:处理转录文本、会话状态和关闭流程。
SIP 是一种 用于通过互联网拨打电话的协议。使用 SIP 和 Realtime API,您可以将来电转接到 API。
概览
如果您想将电话号码连接到 Realtime API,请使用 SIP 中继提供商(例如 Twilio)。这种服务会将您的电话通话转换为 IP 流量。向 SIP 中继提供商购买电话号码后,请按照以下说明操作。
首先,前往 platform.openai.com 的设置 > 项目 > Webhook,为来电创建 Webhook。
然后,使用您为其配置 Webhook 的项目 ID,
将 SIP 中继指向 OpenAI SIP 端点,例如 sip:$PROJECT_ID@sip.api.openai.com;transport=tls。
如需欧洲数据驻留,请改用 sip:$PROJECT_ID@sip-eu.api.openai.com;transport=tls。
要查找您的 $PROJECT_ID,请前往设置 > 项目 > 常规。该页面会显示项目 ID,
其前缀为 proj_。
当 OpenAI 收到与您的项目关联的 SIP 流量时,
就会触发您的 Webhook。触发的事件为
realtime.call.incoming 事件,
如下例所示:
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"}
]
}
}收到此 Webhook 后,您可以使用其中的 call_id 值来接听或拒接通话。
接听通话时,您需要为 Realtime API 会话提供所需配置
(指令、语音等)。
会话建立后,您可以设置 WebSocket,并像往常一样监控会话。下文介绍了用于
接听、拒接、监控、转接和挂断通话的 API。
接听通话
使用接听通话端点,
允许接听来电,并配置用于应答的实时会话。
发送的参数应与
create client secret
请求中的参数相同,也就是说,在将通话
桥接到模型之前,请确保已设置实时模型、语音、工具或指令。
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."
}'请求路径必须包含来自
realtime.call.incoming
Webhook 的 call_id,且每个请求都需要带上上述 Authorization 标头。
当 SIP 呼叫段开始振铃且实时会话
正在建立时,该端点会返回 200 OK。
拒接通话
当您不想处理来电时(例如来电的国家/地区代码不受支持),可使用拒接来电端点
拒绝呼叫邀请。
请提供 call_id 路径参数,
并在 JSON 请求体中提供可选的 SIP status_code(例如,用 486 表示“忙线”),
以控制返回给运营商的响应。
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}'如果未提供状态码,API 默认使用 603 Decline。
请求成功时,OpenAI 会在发送 SIP 响应后
返回 200 OK。
监控通话事件
接受来电后,请建立连接到同一会话的 WebSocket 连接,
以流式接收事件并发出实时命令。请注意,
使用 call_id 参数连接现有通话时,不会使用 model 参数(因为模型已经
通过 accept 端点配置)。
WebSocket 请求
GET wss://api.openai.com/v1/realtime?call_id={call_id}
查询参数
| 参数 | 类型 | 说明 |
|---|---|---|
call_id | 字符串 | 来自 realtime.call.incoming Webhook 的标识符。 |
请求头
Authorization: Bearer YOUR_API_KEY
此 WebSocket 的行为与其他 Realtime API 连接完全相同。发送
response.create
和其他客户端事件来控制通话,并监听服务器事件,
以跟踪进展。请参阅Webhook 与服务器端控制
了解更多信息。
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",
})
);
});转接通话
使用
转接通话端点转接正在进行的通话。请提供
call_id,以及应填入 SIP Refer-To 标头的 target_uri
(例如 tel:+14155550123 或 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"}'REFER 转发至您的 SIP 提供商后,OpenAI 即返回 200 OK。
下游系统会为主叫方处理后续通话流程。
挂断通话
当您的应用需要断开主叫方的连接时,使用挂断端点 结束会话。此端点可用于 终止 SIP 和 WebRTC 实时会话。
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/hangup" \
-H "Authorization: Bearer $OPENAI_API_KEY"API 开始拆除通话连接时,会返回 200 OK。
SIP 信令和媒体 IP 范围
Realtime SIP 通话使用不同的网络路径传输信令和媒体。为确保正常运行, 请按下文说明配置网络,允许信令和媒体流量通过。
SIP 信令
sip.api.openai.com 和 sip-eu.api.openai.com 是通过 GeoIP 路由的端点。您的网络必须允许
发往 DNS 返回地址的 5061 端口的出站 TCP/TLS 流量。
SRTP 媒体
API 会在协商的 SDP 中指定独立的媒体 IP 地址和 UDP 端口。您的网络必须 允许通过 UDP 与以下 CIDR 网段双向传输 SRTP 流量:
13.79.45.80/2823.98.140.64/2840.67.149.176/2840.83.204.240/28
服务器示例
以下是 realtime.call.incoming 处理程序的示例。它会接受来电,然后将
来自 Realtime API 的所有事件记录到日志中。
运行 Ruby 示例前,请设置 OPENAI_API_KEY 和 OPENAI_WEBHOOK_SECRET
环境变量,然后使用以下命令安装所需依赖项:
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)
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,
)
threading.Thread(
target=lambda: asyncio.run(websocket_task(event.data.call_id)),
daemon=True,
).start()
return Response(status=200)
except InvalidWebhookSignatureError as e:
print("Invalid signature", e)
return Response("Invalid signature", status=400)
if __name__ == "__main__":
app.run(port=8000)后续步骤
您已通过 SIP 建立连接,现在可使用左侧导航或点击进入以下页面,开始构建您的实时应用。