> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# SMS OTP 验证

![智能体对话中收集电话号码、OTP 代码并完成验证](/docs/_fern-img/97201c6fdad0c63900236b52726c867d3ff9405fdbd30725858f384653c95803.webp)

## 概述

本指南介绍如何将 [Twilio Verify](https://www.twilio.com/docs/verify/api) 集成到 ElevenLabs 智能体，以便在实时语音对话中向来电者的电话号码发送 OTP，并验证对方读出的验证码。

你将了解如何：

* 创建 Twilio Verify 服务，并对凭据进行 Base64 编码以完成身份验证。
* 在[控制台](https://elevenlabs.io/app/agents)、使用 [Agents CLI](/docs/zh/eleven-agents/operate/cli) 或通过 [ElevenLabs API](/docs/zh/api-reference/introduction) 配置两个 webhook 工具（`send_SMS_verification` 和 `check_SMS_verification`）。
* 使用包含密钥值的 `Authorization` 请求头验证两个 webhook 调用。
* 启用 [`skip_turn`](/docs/zh/eleven-agents/customization/tools/system-tools/skip-turn) 系统工具，以便来电者尚未收到验证码时，智能体可以等待。

## 前提条件

* 已启用 [Twilio Verify](https://www.twilio.com/docs/verify/api) 的 Twilio 账户。如果 Twilio Console 中没有 Verify，请通过 [Twilio 支持](https://support.twilio.com/)或 Twilio 客户团队申请访问权限。
* 如果 Twilio 账户处于[试用模式](https://www.twilio.com/docs/guides/how-to-use-your-free-trial-account)，目标电话号码必须是 Twilio 中已验证的来电显示号码。

#### 登录 Twilio Console

打开 [Twilio Console](https://console.twilio.com/)。

#### 创建 Authenticate（Verify）服务

在左侧边栏中选择 **Add +**，然后创建一个 **Authenticate**（Verify）服务。

#### 命名服务

为服务指定一个描述性名称（例如 `ElevenLabs OTP`）。

#### 复制 Verify Service SID

打开服务的 **Settings** 页面并复制 **Verify Service SID**。它以 `VA` 开头，与 Account SID 不同。

> **Warning**
>
> **常见错误**：在下方工具 URL 中使用 Authenticate（Verify）服务的 **Verify Service SID**（`VA...`）。不要将 **Account SID**（`AC...`）放入路径中。Verify API 要求在 URL 中使用服务 SID；使用 Account SID 会导致 `4xx` 无效参数错误。

可使用控制台中的 Twilio API Explorer 测试请求，然后再将其连接到智能体。

### 编码凭据并配置 webhook 工具

#### 为 Basic 身份验证编码 Twilio 凭据

Twilio Verify 使用 HTTP Basic 身份验证，其中 **Account SID** 为用户名，**Auth Token** 为密码。可在 [Twilio Console](https://console.twilio.com/) 首页的 **Account Info** 下找到两者。

在 shell 中对 `ACCOUNT_SID:AUTH_TOKEN` 进行 Base64 编码（以冒号分隔，不含空格）：

```bash
printf '%s' 'YOUR_ACCOUNT_SID:YOUR_AUTH_TOKEN' | base64
```

复制输出内容。完整的 `Authorization` 请求头值由 `Basic` 一词、一个空格和该 Base64 字符串组成。在接下来的步骤中将其保存为工具密钥。

```text
Basic dkFDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
```

#### 配置 \`send_SMS_verification\` 和 \`check_SMS_verification\` 工具

`send_SMS_verification` 调用 Twilio Verify 发送 SMS OTP。`check_SMS_verification` 提交来电者说出的数字。两者都需要相同的 Verify Service SID 和 `Authorization` 密钥。

#### 通过控制台添加

### send_SMS_verification

![智能体对话中收集电话号码、OTP 代码并完成验证](/docs/_fern-img/9d72a753674c17481e99ea871b1b178cd7791f2da1ec3491ad4786c3fbc9a84e.webp)

在智能体设置的 **Agent** 部分中，选择 **Add Tool**，然后选择 **Webhook**。

| 字段  | 值                                                                             |
| --- | ----------------------------------------------------------------------------- |
| 名称  | `send_SMS_verification`                                                       |
| 描述  | 通过 SMS 向提供的电话号码发送 OTP 验证码                                                     |
| 方法  | `POST`                                                                        |
| URL | `https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/Verifications` |

将 `YOUR_VERIFY_SERVICE_SID` 替换为第一步中的 `VA...` SID。

**身份验证请求头：** 在 **Headers** 下添加 `Authorization`，类型选择 **Secret**，然后粘贴完整值（`Basic ` 加 Base64）。请参阅 [Webhook 工具](/docs/zh/eleven-agents/customization/tools/webhook-tools)。

**请求体参数：** 将 **Content type** 设为 **URL-encoded**（`application/x-www-form-urlencoded`）。添加以下参数，并将值类型设为 **LLM Prompt**：

| 数据类型     | 标识符       | 描述                                  |
| -------- | --------- | ----------------------------------- |
| `string` | `To`      | E.164 格式的来电者电话号码（例如 `+14155552671`） |
| `string` | `Channel` | 发送渠道；使用 `sms`                       |

### check_SMS_verification

添加第二个 webhook 工具：

| 字段  | 值                                                                                 |
| --- | --------------------------------------------------------------------------------- |
| 名称  | `check_SMS_verification`                                                          |
| 描述  | 检查来电者提供的 OTP 验证码是否有效                                                              |
| 方法  | `POST`                                                                            |
| URL | `https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/VerificationCheck` |

使用与 `send_SMS_verification` 相同的 Verify Service SID 和 `Authorization` 密钥。

**请求体参数：** 使用 **URL-encoded**。通过 **LLM Prompt** 添加 `To`（E.164）和 `Code`（OTP 数字）。

#### 通过 CLI 添加

> **Note**
>
> 创建一个[工作区密钥](/docs/zh/api-reference/workspace/secrets/create)，其值为完整的 `Authorization` 请求头（`Basic ` 加 Base64）。在下方 JSON 中将该密钥 ID 填入 `YOUR_SECRET_ID`。

#### 添加工具配置文件

将发送工具保存为 `tool_configs/send_SMS_verification.json`（将 `YOUR_VERIFY_SERVICE_SID` 替换为 `VA...` SID）：

```json
{
  "type": "webhook",
  "name": "send_SMS_verification",
  "description": "Sends an OTP verification code via SMS to the provided phone number",
  "api_schema": {
    "url": "https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/Verifications",
    "method": "POST",
    "content_type": "application/x-www-form-urlencoded",
    "request_headers": {
      "Authorization": { "secret_id": "YOUR_SECRET_ID" }
    },
    "request_body_schema": {
      "type": "object",
      "description": "Twilio Verify start verification parameters",
      "required": ["To", "Channel"],
      "properties": {
        "To": {
          "type": "string",
          "description": "Caller phone number in E.164 format (for example +14155552671)"
        },
        "Channel": {
          "type": "string",
          "constant_value": "sms"
        }
      }
    }
  }
}
```

将验证工具保存为 `tool_configs/check_SMS_verification.json`：

```json
{
  "type": "webhook",
  "name": "check_SMS_verification",
  "description": "Checks whether the OTP code provided by the caller is valid",
  "api_schema": {
    "url": "https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/VerificationCheck",
    "method": "POST",
    "content_type": "application/x-www-form-urlencoded",
    "request_headers": {
      "Authorization": { "secret_id": "YOUR_SECRET_ID" }
    },
    "request_body_schema": {
      "type": "object",
      "description": "Twilio Verify verification check parameters",
      "required": ["To", "Code"],
      "properties": {
        "To": {
          "type": "string",
          "description": "Same caller number in E.164 format"
        },
        "Code": {
          "type": "string",
          "description": "The OTP digits the caller provided"
        }
      }
    }
  }
}
```

#### 注册工具

```bash
elevenlabs tools add "send_SMS_verification" --type "webhook" --config-path ./tool_configs/send_SMS_verification.json
elevenlabs tools add "check_SMS_verification" --type "webhook" --config-path ./tool_configs/check_SMS_verification.json
```

#### 将工具添加到智能体

编辑 `agent_configs/<agent-name>.json`。在 `conversation_config.agent.prompt` 下，将 `tool_ids` 设为包含这两个工具（使用 `tools.json` 或 `elevenlabs agents tools list` 中的 ID）。然后推送：

```bash
elevenlabs agents push --agent "<agent-name>"
```

#### 通过 API 添加

> **Note**
>
> 创建一个[工作区密钥](/docs/zh/api-reference/workspace/secrets/create)来保存完整的 `Basic ...` 请求头值，然后在 `request_headers` 中将其 ID 作为 `secret_id` 传入。

```python
from elevenlabs import ElevenLabs, ToolRequestModel

elevenlabs = ElevenLabs()

send_sms = elevenlabs.conversational_ai.tools.create(
    request=ToolRequestModel(
        tool_config={
            "type": "webhook",
            "name": "send_SMS_verification",
            "description": "Sends an OTP verification code via SMS to the provided phone number",
            "api_schema": {
                "url": "https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/Verifications",
                "method": "POST",
                "content_type": "application/x-www-form-urlencoded",
                "request_headers": {
                    "Authorization": {"secret_id": "YOUR_SECRET_ID"},
                },
                "request_body_schema": {
                    "type": "object",
                    "description": "Twilio Verify start verification parameters",
                    "required": ["To", "Channel"],
                    "properties": {
                        "To": {
                            "type": "string",
                            "description": "Caller phone number in E.164 format (for example +14155552671)",
                        },
                        "Channel": {
                            "type": "string",
                            "constant_value": "sms",
                        },
                    },
                },
            },
        }
    )
)

check_sms = elevenlabs.conversational_ai.tools.create(
    request=ToolRequestModel(
        tool_config={
            "type": "webhook",
            "name": "check_SMS_verification",
            "description": "Checks whether the OTP code provided by the caller is valid",
            "api_schema": {
                "url": "https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/VerificationCheck",
                "method": "POST",
                "content_type": "application/x-www-form-urlencoded",
                "request_headers": {
                    "Authorization": {"secret_id": "YOUR_SECRET_ID"},
                },
                "request_body_schema": {
                    "type": "object",
                    "description": "Twilio Verify verification check parameters",
                    "required": ["To", "Code"],
                    "properties": {
                        "To": {
                            "type": "string",
                            "description": "Same caller number in E.164 format",
                        },
                        "Code": {
                            "type": "string",
                            "description": "The OTP digits the caller provided",
                        },
                    },
                },
            },
        }
    )
)

elevenlabs.conversational_ai.agents.update(
    agent_id="agent_7101k5zvyjhmfg983brhmhkd98n6",
    conversation_config={
        "agent": {
            "prompt": {
                "tool_ids": [send_sms.id, check_sms.id],
            },
        },
    },
)
```

```typescript
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const elevenlabs = new ElevenLabsClient();

const sendSms = await elevenlabs.conversationalAi.tools.create({
  toolConfig: {
    type: "webhook",
    name: "send_SMS_verification",
    description: "Sends an OTP verification code via SMS to the provided phone number",
    apiSchema: {
      url: "https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/Verifications",
      method: "POST",
      contentType: "application/x-www-form-urlencoded",
      requestHeaders: {
        Authorization: { secretId: "YOUR_SECRET_ID" },
      },
      requestBodySchema: {
        type: "object",
        description: "Twilio Verify start verification parameters",
        required: ["To", "Channel"],
        properties: {
          To: {
            type: "string",
            description: "Caller phone number in E.164 format (for example +14155552671)",
          },
          Channel: {
            type: "string",
            constantValue: "sms",
          },
        },
      },
    },
  },
});

const checkSms = await elevenlabs.conversationalAi.tools.create({
  toolConfig: {
    type: "webhook",
    name: "check_SMS_verification",
    description: "Checks whether the OTP code provided by the caller is valid",
    apiSchema: {
      url: "https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/VerificationCheck",
      method: "POST",
      contentType: "application/x-www-form-urlencoded",
      requestHeaders: {
        Authorization: { secretId: "YOUR_SECRET_ID" },
      },
      requestBodySchema: {
        type: "object",
        description: "Twilio Verify verification check parameters",
        required: ["To", "Code"],
        properties: {
          To: {
            type: "string",
            description: "Same caller number in E.164 format",
          },
          Code: {
            type: "string",
            description: "The OTP digits the caller provided",
          },
        },
      },
    },
  },
});

await elevenlabs.conversationalAi.agents.update("agent_7101k5zvyjhmfg983brhmhkd98n6", {
  conversationConfig: {
    agent: {
      prompt: {
        toolIds: [sendSms.id, checkSms.id],
      },
    },
  },
});
```

> **Note**
>
> 如果在控制台中将 **`Channel`** 配置为由 LLM 填充的字段，请在系统提示词中添加说明，确保模型始终传入 `sms`。上方 CLI 和 API 示例使用 `constant_value` / `constantValue` 固定 `sms`，因此模型不会选择渠道。

#### 启用 \`skip_turn\` 系统工具

来电者通常需要一点时间接收 SMS，之后才能读出验证码。若不使用 `skip_turn`，智能体可能会打断停顿或重复提示。

#### 通过控制台添加

在 **Tools** 中选择 **Add Tool**，选择 **System tool**，然后启用 **Skip turn**。无需进一步配置。

#### 通过 CLI 添加

在 `agent_configs/<agent-name>.json` 的 `conversation_config.agent.prompt` 下，将 `built_in_tools.skip_turn` 设为 `null`（默认值）以启用 Skip turn，然后运行：

```bash
elevenlabs agents push --agent "<agent-name>"
```

#### 通过 API 添加

```python
from elevenlabs import ElevenLabs

elevenlabs = ElevenLabs()

elevenlabs.conversational_ai.agents.update(
    agent_id="agent_7101k5zvyjhmfg983brhmhkd98n6",
    conversation_config={
        "agent": {
            "prompt": {
                "built_in_tools": {
                    "skip_turn": None,
                },
            },
        },
    },
)
```

```typescript
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const elevenlabs = new ElevenLabsClient();

await elevenlabs.conversationalAi.agents.update("agent_7101k5zvyjhmfg983brhmhkd98n6", {
  conversationConfig: {
    agent: {
      prompt: {
        builtInTools: {
          skipTurn: null,
        },
      },
    },
  },
});
```

如果创建 webhook 工具时已设置 `tool_ids`，请将 `built_in_tools` 合并到同一个 `prompt` 对象中，而不是替换它。

在系统提示词中添加指引，让模型知道何时调用该工具，例如：

```text
When the caller indicates they are still waiting to receive the OTP code — for example,
"hold on", "I haven't received it yet", or "give me a second" — use the skip_turn tool
to wait silently rather than speaking. Do not repeat the prompt or ask for the code again
until the caller indicates they are ready.
```

有关详细信息，请参阅 [Skip turn](/docs/zh/eleven-agents/customization/tools/system-tools/skip-turn)。

#### 在系统提示词中编排流程

使用清晰排列工具调用顺序的系统提示词，例如：

```text
You are a secure verification agent. When you need to verify a caller's identity:

1. Ask for their phone number if you do not already have it.
2. Standardize the number to E.164 for tool calls: a leading plus, country code, then digits only, no spaces (for example +14155552671).
3. Call send_SMS_verification with their number and Channel set to "sms".
4. Tell the caller: "I've sent a verification code to your phone. Please read it out when you're ready."
5. If the caller says they haven't received the code yet or asks for a moment, use skip_turn to wait silently.
6. Once the caller provides the code, call check_SMS_verification with their number and the code.
7. If the response status is "approved", proceed with the verified flow.
8. If the code is invalid, let the caller know and offer to resend.
```

## 故障排除

### Twilio `60200` — 无效参数（HTTP 400）

当请求 URL 或请求体不符合 Verify API 的要求时，Twilio 可能会返回如下响应体：

```json
{
  "code": 60200,
  "message": "Invalid parameter",
  "more_info": "https://www.twilio.com/docs/errors/60200",
  "status": 400
}
```

**检查项：** 路径必须使用 Authenticate（Verify）服务设置中的 **Verify Service SID**（`VA...`）。在 `.../Services/{Sid}/...` 中填入 **Account SID**（`AC...`）是导致 `60200` 的常见原因。其他无效参数情况请参阅 Twilio 的 [60200](https://www.twilio.com/docs/errors/60200) 文档。

### Twilio `20003` — 身份验证错误 — 未提供凭据（HTTP 401）

当 `Authorization` 请求头缺失、格式错误或未发送时，Twilio 可能会响应：

```json
{
  "code": 20003,
  "message": "Authentication Error - No credentials provided",
  "more_info": "https://www.twilio.com/docs/errors/20003",
  "status": 401
}
```

**检查项：** 工具必须发送 `Authorization` 请求头，其值应为完整的 `Basic <base64>` 字符串（包括 `Basic` 一词及其后 Base64 输出前的一个空格）。Base64 输入必须严格为 `ACCOUNT_SID:AUTH_TOKEN`，不能包含额外的空格或换行。确认两个 webhook 工具的此请求头都已关联该密钥。请参阅 [20003](https://www.twilio.com/docs/errors/20003)。

### 其他问题

* **试用模式下号码被拒绝：** 在 Twilio Console 中打开[已验证的电话号码](https://console.twilio.com/us1/develop/phone-numbers/manage/verified)，确认测试前目标号码已列出。
* **智能体打断来电者：** 确认已启用 **Skip turn**，且系统提示词指示模型在来电者需要时间时使用 `skip_turn`。