Speech to Speech API
SIP 电话呼叫
SIP 可将 PSTN、呼叫中心或 PBX 呼叫路由到 Speech to Speech API 会话。
1. 注册电话号码
创建 Direct SIP 电话号码,并填写用于接收来电事件的 webhook 详细信息。对于客户自有号码,请使用 origin: "byo_trunk"。不支持通过 API 配置 xAI 电话号码。xAI 会在响应中返回 webhook 签名密钥。
请选择一种 SIP 身份验证方式。
注册电话号码后,响应会包含签名密钥。请安全存储;xAI 只会返回一次。
配置运营商或 PBX,将呼叫路由到:
curl -X POST "https://api.x.ai/v2/phone-numbers" \
-H "Authorization: Bearer $XAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"origin": "byo_trunk",
"name": "Support SIP trunk",
"phone_number": "+18005550199",
"webhook": {
"name": "Support SIP webhook",
"url": "https://example.com/xai/sip-webhook"
},
"sip_auth": {
"allowed_addresses": ["203.0.113.0/24"]
}
}'如果提供 allowed_addresses,请确保列表包含服务商的 SIP 信令 CIDR 范围。如果提供 SIP 摘要凭据,请在运营商处配置相同的用户名和密码;创建后 xAI 不会再返回该密码。
2. 处理来电 webhook
当呼叫者拨打该号码时,xAI 会向 webhook URL 发送带签名的 realtime.call.incoming webhook。使用注册电话号码后返回的签名密钥验证 webhook-id、webhook-timestamp和webhook-signature 请求头,然后从负载中读取 data.call_id。
webhook 结构如下:
{
"object": "event",
"id": "evt_123",
"type": "realtime.call.incoming",
"created_at": 1750000000,
"data": {
"call_id": "00000000-0000-0000-0000-000000000000",
"sip_headers": [
{ "name": "From", "value": "+14155550100" },
{ "name": "To", "value": "+18005550199" }
],
"metadata": {}
}
}3. 通过 WebSocket 加入呼叫
使用 xAI API key 打开 wss://api.x.ai/v1/realtime?call_id={call_id}。然后发送 session.update,为该呼叫配置语音智能体;当智能体应开始说话时,再发送 response.create。
连接后,WebSocket 的行为与其他 Speech to Speech API 会话相同。SIP 呼叫者的音频会桥接到会话中,助手音频则会播放给呼叫者。
import asyncio
import json
import os
import websockets
async def handle_sip_call(call_id: str):
async with websockets.connect(
f"wss://api.x.ai/v1/realtime?call_id={call_id}",
additional_headers={"Authorization": f"Bearer {os.environ['XAI_API_KEY']}"},
) as ws:
await ws.send(json.dumps({
"type": "session.update",
"session": {
"voice": "eve",
"instructions": "You are a helpful phone support agent.",
"turn_detection": {"type": "server_vad"},
},
}))
await ws.send(json.dumps({"type": "response.create"}))
async for msg in ws:
event = json.loads(msg)
print(event["type"])
asyncio.run(handle_sip_call("00000000-0000-0000-0000-000000000000"))呼叫控制
使用 refer 将来电者转接到另一个 PSTN 或 SIP 目标。请求会阻塞,直至转接结束;HTTP 状态表示目标是否已接听。状态码、转接失败后的会话行为以及对话恢复请参阅 常见问题。
curl -X POST "https://api.x.ai/v1/realtime/calls/$CALL_ID/refer" \
-H "Authorization: Bearer $XAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target_uri": "sip:agent@example.com"}'使用 hangup,在应用需要结束呼叫时使用:
curl -X POST "https://api.x.ai/v1/realtime/calls/$CALL_ID/hangup" \
-H "Authorization: Bearer $XAI_API_KEY"DTMF 电话按键
通过 SIP 使用 Speech to Speech API 时,电话按键(DTMF 音)会自动缓冲,并作为文本输入提交给模型。客户端会收到 input_audio_buffer.dtmf_event_received 事件,作为每次按键的审计记录。
提交触发条件
出现以下任一情况时,缓冲的数字会提交给模型:
用户按下
#(提交键)最后一次按键后空闲 2.5 秒
用户开始说话(抢占数字缓冲区)
审计事件
每次按键都会报告给客户端 WebSocket:
{
"type": "input_audio_buffer.dtmf_event_received",
"event": "5",
"received_at": 1730000000
}电话服务商
无论使用哪个服务商,目标都应设为已注册号码对应的 xAI SIP URI:
将 {number} 替换为 Direct SIP 电话号码。如果注册号码时配置了 allowed_addresses,请包含服务商的 SIP 信令 CIDR 范围。
Twilio
在 Twilio Console 中,前往 Voice → Elastic SIP Trunking 并创建中继。
打开中继的 Origination 设置,并添加该 origination URI:
sip:{number}@sip.voice.x.ai;transport=tls。为中继分配 Twilio 电话号码,或购买新号码并将其附加到中继。
如果应用在会话中途转接呼叫,请在中继上启用呼叫转移。
Telnyx
在 Telnyx Portal 中,前往 Voice Suite → SIP Trunking 并创建 FQDN SIP Connection。
在 Authentication and Routing 中,将
sip.voice.x.ai添加为 primary FQDN,port 为5060,record type 为A。在 Inbound settings 中,将目标号码格式设置为 E.164。
至少启用一种受支持的 codec:G.711 μ-law、G.711 A-law 或 G.722。
为 SIP 连接分配电话号码。
Plivo
在 Plivo Console 中,前往 SIP Trunking 并创建 SIP trunk。
选择 Inbound,然后使用 FQDN
sip.voice.x.ai。将现有电话号码链接到 trunk,或购买新号码并附加到 trunk。
使用自有 SIP 服务商
在运营商、呼叫中心或 PBX 中创建出站路由或 SIP 中继。
将目标设置为
sip:{number}@sip.voice.x.ai;transport=tls。
常见问题
以下解答涵盖语音转语音 API 的 SIP 调用流程:带原因代码的转接成功或失败结果、转接失败时的行为,以及如何在之后的 SIP 通话中继续对话。
如何获取转接成功或失败结果及原因代码?
没有单独的 WebSocket 转接事件。POST /v1/realtime/calls/{call_id}/refer 会同步返回结果。
返回 200 且 JSON 响应体为空({})表示转接已完成:REFER 成功且目标已接听,而不只是 REFER 被接受或目标开始振铃。
下游 SIP 拒绝会返回 502,响应体包含运营商的 SIP 状态:
{
"error": "transfer rejected by downstream: SIP 403 Forbidden"
}还可能出现以下状态:
| 状态 | 含义 |
|---|---|
400 | target_uri 不是 tel: 或 sip: URI |
404 | 此通话中没有 SIP 参与者 |
502 | 下游拒绝转接;如可用,响应体包含 SIP 状态码和原因 |
504 | 转接超时 |
500 | 内部错误 |
转接失败后,会话还能继续使用吗?
可以。REFER 等待处理期间,WebSocket 保持打开,来电者会听到拨号音。返回 502 后,原有实时会话仍保持连接。转接失败不会改变 xAI 侧的通话状态:来电者仍在线,Agent 可以继续交谈。
此流程不会自动开始新会话,也不会注入解释失败原因的 prompt。如果需要 Agent 向来电者说明失败原因,请读取 refer 的 HTTP 响应并在当前会话中继续,或按下述方式稍后恢复。
能将恢复的对话关联到新的 SIP 通话吗?
会话恢复会缓存转录文本和工具结果,让之后的 SIP 通话继续同一段对话。你必须在原始会话和恢复会话中都显式启用此功能。历史记录在闲置 30 分钟后过期。
第一次通话时,打开
wss://api.x.ai/v1/realtime?call_id={call_id}并立即发送session.update,将resumption.enabled设为true。保存该call_id。。之后通话时,打开
wss://api.x.ai/v1/realtime?call_id={new_call_id}&conversation_id={saved_call_id}并再次发送相同的session.update。这会恢复之前的轮次,并继续保存,以便后续重新连接。没有专门的恢复完成事件。该
session.update处理完成后立即恢复;重放的轮次以conversation.item.created事件到达。
{
"type": "session.update",
"session": {
"resumption": { "enabled": true }
}
}可以转接到 Twilio SIP Domain 吗?
可以。类型为 sip: target_uri 会作为 SIP Refer-To 的值转发,包括用于路由到 Twilio Programmable Voice SIP Domain 或会议的 URI 参数。REFER 不会发送自定义 SIP 请求头。
最后更新:2026 年 8 月 25 日