Speech to Speech API

SIP 电话呼叫

查看 Markdown

SIP 可将 PSTN、呼叫中心或 PBX 呼叫路由到 Speech to Speech API 会话。

1. 注册电话号码

创建 Direct SIP 电话号码,并填写用于接收来电事件的 webhook 详细信息。对于客户自有号码,请使用 origin: "byo_trunk"。不支持通过 API 配置 xAI 电话号码。xAI 会在响应中返回 webhook 签名密钥。

请选择一种 SIP 身份验证方式。

注册电话号码后,响应会包含签名密钥。请安全存储;xAI 只会返回一次。

配置运营商或 PBX,将呼叫路由到:

Bash

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-idwebhook-timestampwebhook-signature 请求头,然后从负载中读取 data.call_id

webhook 结构如下:

JSON

{
  "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 状态表示目标是否已接听。状态码、转接失败后的会话行为以及对话恢复请参阅 常见问题

Bash

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,在应用需要结束呼叫时使用:

Bash

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:

JSON

{
  "type": "input_audio_buffer.dtmf_event_received",
  "event": "5",
  "received_at": 1730000000
}

电话服务商

无论使用哪个服务商,目标都应设为已注册号码对应的 xAI SIP URI:

{number} 替换为 Direct SIP 电话号码。如果注册号码时配置了 allowed_addresses,请包含服务商的 SIP 信令 CIDR 范围。

Twilio

  1. 在 Twilio Console 中,前往 VoiceElastic SIP Trunking 并创建中继。

  2. 打开中继的 Origination 设置,并添加该 origination URI:sip:{number}@sip.voice.x.ai;transport=tls

  3. 为中继分配 Twilio 电话号码,或购买新号码并将其附加到中继。

  4. 如果应用在会话中途转接呼叫,请在中继上启用呼叫转移。

Telnyx

  1. 在 Telnyx Portal 中,前往 Voice SuiteSIP Trunking 并创建 FQDN SIP Connection。

  2. Authentication and Routing 中,将 sip.voice.x.ai 添加为 primary FQDN,port 为 5060,record type 为 A

  3. Inbound settings 中,将目标号码格式设置为 E.164

  4. 至少启用一种受支持的 codec:G.711 μ-law、G.711 A-law 或 G.722。

  5. 为 SIP 连接分配电话号码。

Plivo

  1. 在 Plivo Console 中,前往 SIP Trunking 并创建 SIP trunk。

  2. 选择 Inbound,然后使用 FQDN sip.voice.x.ai

  3. 将现有电话号码链接到 trunk,或购买新号码并附加到 trunk。

使用自有 SIP 服务商

  1. 在运营商、呼叫中心或 PBX 中创建出站路由或 SIP 中继。

  2. 将目标设置为 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 状态:

JSON

{
  "error": "transfer rejected by downstream: SIP 403 Forbidden"
}

还可能出现以下状态:

状态含义
400target_uri 不是 tel:sip: URI
404此通话中没有 SIP 参与者
502下游拒绝转接;如可用,响应体包含 SIP 状态码和原因
504转接超时
500内部错误

转接失败后,会话还能继续使用吗?

可以。REFER 等待处理期间,WebSocket 保持打开,来电者会听到拨号音。返回 502 后,原有实时会话仍保持连接。转接失败不会改变 xAI 侧的通话状态:来电者仍在线,Agent 可以继续交谈。

此流程不会自动开始新会话,也不会注入解释失败原因的 prompt。如果需要 Agent 向来电者说明失败原因,请读取 refer 的 HTTP 响应并在当前会话中继续,或按下述方式稍后恢复。

能将恢复的对话关联到新的 SIP 通话吗?

会话恢复会缓存转录文本和工具结果,让之后的 SIP 通话继续同一段对话。你必须在原始会话和恢复会话中都显式启用此功能。历史记录在闲置 30 分钟后过期。

  1. 第一次通话时,打开 wss://api.x.ai/v1/realtime?call_id={call_id} 并立即发送 session.update,将 resumption.enabled 设为 true。保存该 call_id

  2. 。之后通话时,打开 wss://api.x.ai/v1/realtime?call_id={new_call_id}&conversation_id={saved_call_id} 并再次发送相同的 session.update。这会恢复之前的轮次,并继续保存,以便后续重新连接。

  3. 没有专门的恢复完成事件。该 session.update 处理完成后立即恢复;重放的轮次以 conversation.item.created 事件到达。

JSON

{
  "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 日