English
主导航

旧版 API

通过 SIP 使用 Realtime API

使用 SIP 连接到 Realtime API。

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/28 for northeurope
  • 23.98.140.64/28 for southcentralus
  • 40.67.149.176/28 for eastus2
  • 40.83.204.240/28 for westus

Python 示例

以下是一个 realtime.call.incoming 处理程序的示例。它接受呼叫,然后记录来自 Realtime API 的所有事件。

Python
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 建立连接,请使用左侧导航或点击进入这些页面,开始构建您的实时应用程序。

其他资源