SIP 是一种通过互联网拨打电话的协议。通过 SIP 和 Realtime API,您可以将来电转接到 API。
概览
如果您想将电话号码连接到 Realtime API,请使用 SIP 中继提供商(例如 Twilio)。这项服务可以将您的电话呼叫转换为 IP 流量。从 SIP 中继提供商处购买电话号码后,请按照以下说明操作。
首先,通过您的 网络钩子 (webhook) 为来电创建一个 platform.openai.com 设置 < 项目 < Webhooks。然后,将你的 SIP 中继指向 OpenAI SIP 端点,使用你为其配置了 webhook 的项目 ID,例如, sip:$PROJECT_ID@sip.api.openai.com;transport=tls。要查找你的 $PROJECT_ID,请访问 设置 < 项目 < 综合。该页面将显示项目 ID,其带有一个 proj_ prefix.
当 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,您可以使用 webhook 中的 call_id 值来接听或拒绝呼叫。接听呼叫时,您需要为 Realtime API 会话提供必要的配置(指令、声音等)。建立连接后,您可以像往常一样设置 WebSocket 并监控该会话。用于接听、拒绝、监控、转接和挂断呼叫的 API 记录在下方。
接听呼叫
使用 接听呼叫端点 以批准入站呼叫并配置用于应答的实时会话。请发送与您在
create client secret
请求,即在将呼叫桥接到模型之前,确保已设置 realtime 模型、语音、工具或指令。
1
2
3
4
5
6
7
8
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",
"instructions": "You are Alex, a friendly concierge for Example Corp."
}'请求路径必须包含 call_id from the
realtime.call.incoming
webhook,并且每个请求都需要 Authorization 上述标头。一旦 SIP 端开始响铃且 realtime 会话正在建立, 200 OK 该端点就会返回。
拒绝呼叫
使用 拒绝呼叫端点 用于在您不想处理来电时拒绝邀请(例如,来自不支持的国家/地区代码)。提供 call_id 路径参数以及可选的 SIP status_code (e.g., 486 (在 JSON body 中指示“忙音”)以控制发回给运营商的响应。
1
2
3
4
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 在 OpenAI 交付 SIP 响应之后。
监听呼叫事件
在接听呼叫后,打开一个连接到同一会话的 WebSocket 以流式传输事件并发出 realtime 命令。请注意,当使用 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
请求头
response.create,以及其他控制通话的客户端事件,并监听服务端事件以追踪进度。参见 Webhook 与服务端控制
for more information.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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",
})
);
});WebSocket 的行为与任何其他 Realtime API 连接完全一致。发送
重定向呼叫
使用以下方式转接活动呼叫。提供
call_id 转接呼叫端点 target_uri 以及应放置在 SIP Refer-To
标头中的(例如 tel:+14155550123 or sip:agent@example.com).
1
2
3
4
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 返回 200 OK 一旦 REFER 被中继到您的 SIP 提供商。下游系统将为呼叫者处理其余的呼叫流程。
挂断呼叫
使用以下端点结束会话 挂断端点 当您的应用程序应断开与呼叫者的连接时。此端点可用于终止 SIP 和 WebRTC 实时会话。
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/hangup" \
-H "Authorization: Bearer $OPENAI_API_KEY"The API responds with 200 OK 当它开始拆除呼叫时。
专用 SIP IP 范围
如果您需要将 OpenAI SIP 流量加入允许名单。 sip.api.openai.com 进行 GeoIP 路由,您将连接到距离最近的区域。
13.79.45.80/28fornortheurope23.98.140.64/28forsouthcentralus40.67.149.176/28foreastus240.83.204.240/28forwestus
Python 示例
以下是一个 realtime.call.incoming 处理程序的示例。它接受呼叫,然后记录来自 Realtime API 的所有事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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.getenv("OPENAI_API_KEY")
}
call_accept = {
"type": "realtime",
"instructions": "You are a support agent.",
"model": "gpt-realtime-2",
}
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 建立连接,请使用左侧导航或点击进入这些页面,开始构建您的实时应用程序。