---
title: "事件目录"
description: "ThunderPhone 发出的所有 Webhook 事件类型。"
---

每个 webhook 正文都包含一个 `type` 字段，其值为本页中的某一种事件
类型。当您订阅某个
[端点](/zh/webhooks/endpoints)时，`events` 数组必须包含您需要的
事件类型（或者留空以订阅所有事件——
但每轮事件 [`telephony.turn`](#telephony-turn) /
[`web.turn`](#web-turn) 除外，这些事件仅投递到明确指定它们的
端点）。

这些事件通过两种投递方式传送：

* **端点投递**始终是带有[重试机制](/zh/webhooks/overview)的**非阻塞**通知：使用任意 2xx 响应；信封中包含用于去重的 `event_id`。
* **阻塞式**交互仅在[旧版单 URL webhook](/zh/webhooks/overview)上运行：包括 [`telephony.incoming` / `web.incoming`](/zh/webhooks/call-incoming) 配置请求（webhook 模式号码：13 秒，包含一次重试；webhook 模式小组件密钥：10 秒）以及 webhook 模式[工具调度](/zh/tools/overview)。您的响应将影响实时通话。

以下示例载荷按其在线传输顺序展示端点信封
（键按字母顺序排序：`data`、`event_id`、`type`）；旧版投递包含相同的 `data`，但不含 `event_id`。

## 通话事件

### `telephony.incoming`

当呼入电话接入您的某个[电话号码](/api-reference/phone-numbers)时发送。端点投递是针对**每一通**呼入电话发送后即不再等待的通知，无论该号码配置了智能体还是 webhook。未分配智能体的号码还会在旧版 webhook 上收到**阻塞式**配置请求——完整的请求/响应架构请参阅
[`telephony.incoming` / `web.incoming`](/zh/webhooks/call-incoming)。

```json
{
  "data": {
    "call_id": 987654321,
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  },
  "event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
  "type": "telephony.incoming"
}
```

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |

### `telephony.complete`

当呼入或呼出电话结束时发送。非阻塞。包含转写文本、可用时的录音 URL 以及账单摘要。有关负载架构，请参阅
[`telephony.complete` / `web.complete`](/zh/webhooks/call-complete)。

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |

### `telephony.tool`

电话通话调用[函数工具](/zh/tools/overview)后发送。此为非阻塞审计通知——投递此事件时，工具已执行完毕；它涵盖您自己的函数工具以及内置 `send_sms` 工具（不包括其他内置工具、知识库工具、应用连接工具或 MCP 工具）。对于 `send_sms`，`arguments.to` 和 `arguments.body` 均为 `[REDACTED]`。完成事件的转写文本也会隐藏这些内容；请使用响应中的 `message_id` 从组织范围的 SMS 资源中获取内容和收件人。

```json
{
  "data": {
    "arguments": { "date": "2026-04-21" },
    "call_id": 987654321,
    "from_number": "+14155550199",
    "response": {
      "response": { "available_slots": ["9:00 AM", "2:00 PM"] },
      "status": 200
    },
    "to_number": "+15551234567",
    "tool_name": "search_appointments"
  },
  "event_id": "1f0a7c3e-52d4-4a0e-8f4b-b1a6a1c0d9e2",
  "type": "telephony.tool"
}
```

`response` 是已执行的结果：成功时为 `{"status": <http status>,
"response": <your endpoint's JSON>}`，失败时为
`{"status": <status>, "error": "<message>"}`。

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |

### `telephony.turn`

在电话通话**进行中**发送，每个包含语音的轮次发生时各发送一次——包括智能体的语音回复和来电者的转写轮次。您可以通过普通 webhook 跟进实时对话，无需轮询
[`GET /v1/calls/{call_id}/transcript`](/api-reference/calls#get-transcript)。
非阻塞。

<Note>
  **必须显式订阅。** 与其他所有事件类型不同，轮次事件绝不会通过空的 `events` 数组（订阅全部）投递。只有当端点的 `events` 列表明确包含 `telephony.turn` / `web.turn` 时，端点才会收到这些事件。
</Note>

```json
{
  "data": {
    "call_id": 987654321,
    "entry_type": "completion",
    "from_number": "+14155550199",
    "position": 7,
    "role": "assistant",
    "start_ms": 15200,
    "text": "How many employees does your company have?",
    "to_number": "+15551234567"
  },
  "event_id": "8d3f5a2c-7b1e-4c9a-b6d0-2e4f6a8c0d1e",
  "type": "telephony.turn"
}
```

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |
| `position` | integer | 该轮次在通话记录中的索引——用于排序的稳定标识 |
| `role` | string | `assistant`（智能体语音）或 `user`（来电者语音） |
| `text` | string | 事件发送时已知的该轮次转写文本 |
| `entry_type` | string | 底层通话记录条目类型：`completion`（智能体），或 `user_turn` / `span`（来电者） |
| `start_ms`, `end_ms` | integer | 自通话开始起的音频偏移量，单位为毫秒；仅当事件发送时已知播放时间时存在 |

<Note>
  投递至少一次，且轮次可能会**乱序**到达：请根据信封中的 `event_id` 去重，并按 `position` 排序。来电者转写文本在发送后仍可能进一步修正；通话结束后的 [`telephony.complete`](/zh/webhooks/call-complete) 转写文本为权威版本。仅语音轮次会发送——工具调用、耳语及其他内部条目绝不会出现在此流中。
</Note>

### `web.incoming`

`telephony.incoming` 的 Web 渠道对应事件，在[Web 小组件](/zh/widget/overview)会话或构建器麦克风测试通话开始时发送。端点投递会针对每个 Web 会话发送后即不再等待。`mode="webhook"` 中的可发布密钥还会在旧版 webhook 上收到**阻塞式**配置请求——该阻塞请求的结构不同（`origin_domain`、`publishable_key_prefix`；没有电话号码）。请参阅
[`telephony.incoming` / `web.incoming`](/zh/webhooks/call-incoming)。

```json
{
  "data": {
    "call_id": 987654322,
    "from_number": "web",
    "origin_domain": "https://example.com",
    "publishable_key_prefix": "pk_live_a1b2",
    "to_number": "+15551234567"
  },
  "event_id": "9a2b4c6d-8e0f-4a1b-9c2d-3e4f5a6b7c8d",
  "type": "web.incoming"
}
```

`from_number` 始终为字面量 `"web"`。对于 webhook 模式的小组件会话，`to_number` 为空（会话的智能体号码会在配置后分配）；对于构建器麦克风测试通话，`origin_domain` 和 `publishable_key_prefix` 为空。

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |

### `web.complete`

`telephony.complete` 的 Web 渠道对应事件，涵盖 Web 小组件通话（`direction: "web"`）和构建器麦克风测试通话（`direction: "test"`）。非阻塞。负载结构与
[`telephony.complete`](/zh/webhooks/call-complete) 相同，另加 `origin_domain`，并将 `from_number` 设置为 `"web"`。

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |

<Note>
  在旧版单 URL webhook 上，构建器麦克风测试通话历来报告为 `telephony.complete`——只有 `direction:
  "web"` 通话在该处使用 `web.complete` 类型。端点系统会将 Web 和测试通话都映射为 `web.*`。历史负载可能包含旧版 `direction` 值 `widget` 或 `mic`。
</Note>

### `web.tool`

`telephony.tool` 的 Web 渠道对应事件。`data` 携带 `origin_domain`，而非 `from_number` / `to_number`。

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |

### `web.turn`

[`telephony.turn`](#telephony-turn) 的 Web 渠道对应事件，涵盖 Web 小组件通话和构建器麦克风测试通话。负载结构相同，但使用 `origin_domain` 而非 `from_number` / `to_number`。与 `telephony.turn` 一样，它需要**显式订阅**——绝不会通过空的 `events` 数组投递。

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |

### `call.transfer_completed`

每通电话发送一次，包含[呼叫转接](/zh/guides/call-transfers)的最终结果：冷转接，或语音智能体退出后温转接留下的人工桥接。
该事件为非阻塞事件，仅发送到端点（绝不会发送到旧版单 URL Webhook）。它在通话的 `telephony.complete` 之后到达：当运营商接管通话或转接失败时，或者当 ThunderPhone 桥接通话时，在桥接结束后到达。

```json
{
  "data": {
    "agent_id": 12,
    "agent_name": "Front desk",
    "bridge_kind": "cold_fallback",
    "bridge_seconds": 255,
    "bridge_total_cents": 5,
    "call_id": 987654321,
    "destination": "+15555550102",
    "sip_status": 403,
    "transfer_outcome": "bridged"
  },
  "event_id": "5b0f6c1e-9d2a-5e7b-8c4d-1a2b3c4d5e6f",
  "type": "call.transfer_completed"
}
```

| 字段 | 类型 | 描述 |
|-------|------|-------------|
| `call_id` | integer | 已转接的通话 |
| `agent_id` | integer \| null | 处理该通话的智能体（如已分配） |
| `agent_name` | string \| null | 处理该通话的智能体名称（如已分配） |
| `transfer_outcome` | string | `refer_accepted`：运营商接管了通话。`bridged`：ThunderPhone 自行保持主叫方与目标号码之间的连接，原因可能是运营商拒绝了冷转接，或温转接的智能体已退出。`bridge_unanswered`：运营商拒绝了冷转接，且目标号码未接听 ThunderPhone 自行发起的通话。`failed`：转接未成功，通话已结束 |
| `destination` | string \| null | 通话转接到的号码 |
| `sip_status` | integer \| null | 运营商拒绝冷转接时的 SIP 状态：`403`（例如不支持呼叫转接的 Twilio 中继）、`405` 或 `501`。运营商未拒绝时为 `null` |
| `bridge_kind` | string \| null | 仅限 `bridged`：`cold_fallback`（ThunderPhone 连接的被拒绝冷转接）或 `warm`（智能体退出后温转接中的两个人） |
| `bridge_seconds` | integer \| null | 仅限 `bridged`：ThunderPhone 计费的桥接时长，单位为秒 |
| `bridge_total_cents` | integer \| null | 仅限 `bridged`：扣除任何免费通话额度后的桥接费用，单位为美元分；该费用与通话的 `billing_total_cents` 分开计费 |

[通话对象](/api-reference/calls#call-object)中也包含相同的值，字段为 `transfer_outcome`、`transfer_destination`、`transfer_sip_status`、`transfer_bridge_kind`、`transfer_bridge_seconds` 和 `transfer_bridge_total_cents`。对于同一通话，`event_id` 在每次投递中均相同，因此重复报告不会产生第二个事件。

---

## 短信事件

短信事件描述通过组织已连接的 Twilio 或 Telnyx 账户发送的消息。消息正文会被省略，且 `to` 会被脱敏。当您需要消息内容或收件人时，请通过
[`GET /v1/sms/{message_id}`](/api-reference/sms#retrieve-a-message) 检索组织范围内的消息。

### `sms.sent`

当客户的运营商接受外发短信请求时发送。这不是手机送达回执。

```json
{
  "data": {
    "accepted_at": "2026-09-19T15:42:10.113Z",
    "agent_id": 12,
    "call_id": 987654321,
    "created_at": "2026-09-19T15:42:09.901Z",
    "direction": "outbound",
    "error_code": null,
    "error_message": null,
    "from_number": "+15551234567",
    "id": "313a3117-827b-46e9-a01a-ac1493838724",
    "provider": "twilio",
    "provider_id": "SM0123456789abcdef0123456789abcdef",
    "segment_count": 1,
    "source": "agent_tool",
    "status": "accepted",
    "to": "[REDACTED]"
  },
  "event_id": "0ae347b4-1716-45bb-9a0e-b52373586e37",
  "type": "sms.sent"
}
```

### `sms.failed`

在运营商永久拒绝后、临时重试耗尽后，或结果最终未知时发送。`error_code` 是稳定的 ThunderPhone 代码，`error_message` 会在可用时说明客户需要采取的操作。`status: "unknown"` 表示运营商可能已接受该短信；请在运营商日志中核对，因为 ThunderPhone 不会自动重新发送。

### `sms.received`

预留用于支持入站短信。当前版本不会发出 `sms.received` 事件。入站运营商 webhook 配置和签名验证将单独发布。

---

## 语音事件

自定义语音创建是异步的。这些非阻塞事件让您可以针对最终结果作出响应，而无需轮询[克隆详情端点](/api-reference/custom-voices#list-and-retrieve-clones)。

`voice.ready` 和 `voice.failed` 仅会发送到使用 `events: []` 的组织级端点。无法将它们选为显式事件筛选条件。

### `voice.ready`

当自定义语音完成处理并可分配给智能体时发送。

```json
{
  "data": {
    "voice": {
      "created_at": "2026-07-30T14:12:08.317Z",
      "display_name": "Support voice",
      "failure_reason": "",
      "gender": "female",
      "id": "cv_2f6f90b0e9a34ee8b39be7d1",
      "language": "en",
      "name": "custom:cv_2f6f90b0e9a34ee8b39be7d1",
      "status": "ready",
      "updated_at": "2026-07-30T14:13:31.605Z"
    }
  },
  "event_id": "2d5f0a61-e9b5-4a3c-b684-29d7d9e4b214",
  "type": "voice.ready"
}
```

### `voice.failed`

当自定义语音处理出现永久性失败时发送。

```json
{
  "data": {
    "reason": "audio sample could not be processed",
    "voice": {
      "created_at": "2026-07-30T14:12:08.317Z",
      "display_name": "Support voice",
      "failure_reason": "audio sample could not be processed",
      "gender": "female",
      "id": "cv_2f6f90b0e9a34ee8b39be7d1",
      "language": "en",
      "name": "custom:cv_2f6f90b0e9a34ee8b39be7d1",
      "status": "failed",
      "updated_at": "2026-07-30T14:13:31.605Z"
    }
  },
  "event_id": "3493e985-1a75-4f77-a10a-e74af440cd31",
  "type": "voice.failed"
}
```

| 字段 | 类型 | 描述 |
|-------|------|-------------|
| `voice.id` | string | 自定义语音公开 ID |
| `voice.name` | string | 格式为 `custom:<public_id>` 的智能体语音值 |
| `voice.display_name` | string | 面向组织的语音名称 |
| `voice.language` | string | 克隆语音的单一语言代码 |
| `voice.gender` | string | `male`、`female` 或空字符串 |
| `voice.status` | string | `voice.ready` 对应 `ready`；`voice.failed` 对应 `failed` |
| `voice.failure_reason` | string | 成功时为空；失败时为处理失败详情 |
| `voice.created_at`, `voice.updated_at` | timestamp | ISO 8601 时间戳 |
| `reason` | string | 失败详情；仅在 `voice.failed` 中存在 |

---

## 质量事件

### `call.graded`

每当某个通话的 [AI 评分运行](/api-reference/calls#ai-call-grading)
完成时发送。非阻塞。

```json
{
  "data": {
    "call_id": 987654321,
    "grade": {
      "call_outcome": "success",
      "created_at": "2026-04-20T18:25:11.002Z",
      "detected_issues": [],
      "graded_at": "2026-04-20T18:25:11.002Z",
      "grader_model": "heuristic-v1",
      "id": 5512,
      "score": 92,
      "status": "completed",
      "summary": "Caller asked about their policy and got a full answer…"
    },
    "report": null
  },
  "event_id": "7c1d2e3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
  "type": "call.graded"
}
```

| 字段 | 类型 | 描述 |
|-------|------|-------------|
| `agent_id` | integer \| null | 处理该通话的智能体（如果已分配） |
| `agent_name` | string \| null | 处理该通话的智能体（如果已分配） |
| `grade.id` | integer | 评分 ID |
| `grade.score` | integer \| null | 0–100 |
| `grade.call_outcome` | string | `success`、`failure`、`unknown` 或 `no_conversation` |
| `grade.summary` | string | 单段摘要 |
| `grade.detected_issues` | array | 评分器发现的问题字符串 |
| `grade.status` | string | 始终为 `completed`——仅已完成的运行会发出事件 |
| `grade.grader_model` | string | 生成结果的评分器（例如 `heuristic-v1`） |
| `grade.graded_at`, `grade.created_at` | timestamp | |
| `report` | object \| null | 面向客户的[通话报告](/api-reference/calls#call-report)：结果标签、需关注标记及原因、来电者、单行摘要、来电者体验。在早期启发式评分中，该字段为 `null`，或为字段均为占位符的 `pending` 报告；完整评分的事件会携带已完成的报告 |

<Note>
  一个通话可以被评分多次——快速启发式评分通常会在录音可用后由完整模型评分跟进，也可以手动重新评分。每次完成的运行都会发送各自的 `call.graded` 事件；请将最新的 `graded_at` 视为权威结果。
</Note>

### `call.data_extracted`

每当结构化数据提取成功完成时发送，包括在 `telephony.complete` / `web.complete` 后进行的延迟重试，或通过
[`POST /v1/calls/{call_id}/extract`](/api-reference/calls#run-data-extraction) 手动重新运行。
非阻塞。

在阻塞式提取模式下，完成事件通常最多等待 75 秒的提取预算。如果提取工作进程丢失，生产环境的最终处理排空流程（每五分钟一次）会在开始另一次提取尝试前，发布 `blocking_deadline_at` 已过期的完成事件。后续成功会作为此事件单独发送。

<Warning>
  提取的值是模型对对话的解读。每个非空值都包含其依据的引文、说话者角色和轮次索引，以及运行级验证标记。在涉及资金、身份或访问权限的决策前，请验证结果。
</Warning>

```json
{
  "data": {
    "call_id": 987654321,
    "agent_id": 12,
    "agent_name": "Acme intake",
    "extracted_data": {
      "status": "completed",
      "fields": {
        "customer_name": "Alex Morgan",
        "appointment_date": "2026-04-23"
      },
      "evidence": {
        "customer_name": {
          "quote": "My name is Alex Morgan",
          "speaker_role": "caller",
          "turn_index": 4
        },
        "appointment_date": {
          "quote": "April 23 works for me",
          "speaker_role": "caller",
          "turn_index": 7
        }
      },
      "verification": "verified",
      "field_reasons": {},
      "schema_version": "92850758e231a3c95a..."
    },
    "extracted_at": "2026-04-20T18:25:11.002Z",
    "model": "<model id>",
    "summary": "Alex Morgan called to book a follow-up visit and confirmed Thursday, April 23."
  },
  "event_id": "4d79ef1d-c2b1-4ed6-85b8-8326bd2895ef",
  "type": "call.data_extracted"
}
```

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |
| `summary` | string \| null | 当智能体启用 **生成通话摘要** 时，已完成的[通话摘要](/zh/webhooks/call-complete)。因此，延迟提取事件也会发送错过完成窗口的摘要；否则为 `null`。具有摘要但没有提取字段的智能体绝不会发送此事件：请从 `GET /v1/calls/{call_id}` 读取延迟摘要 |
| `extracted_data.status` | string | 此事件始终为 `completed` |
| `extracted_data.fields` | object | 以已配置提取字段键为键的值；不可用值为 `null` |
| `extracted_data.evidence` | object | 以提取字段为键的证据。非空值包含经过精确结构检查的引文（最多 1,000 个字符）、`speaker_role`（`caller` 或 `agent`）和 `turn_index`；模型返回的较长引文会被拒绝而非截断，并且当其字段为 `null` 时，证据始终为 `null` |
| `extracted_data.verification` | string | 仅当独立证据流程为每个候选字段恰好返回一个有效判定时为 `verified`。`unavailable` 表示该流程失败、超时、预算不足，或返回格式错误或不完整的输出。完全不可用的流程会保留具有结构依据的值，以供客户审核。对于部分输出，会应用有效判定，并将每个没有恰好一个有效判定的候选值设为 null |
| `extracted_data.field_reasons` | object | 因结构依据或独立验证器而被设为空值的字段对应原因 |
| `extracted_data.schema_version` | string | 本次提取所用精确字段架构的哈希值 |
| `extracted_at` | timestamp | ISO 8601 完成时间 |
| `model` | string | 用于提取的模型 |

### `campaign.completed`

当营销活动从 `running` 转为 `completed` 时发送一次，无论是其计划已结束，还是所有联系人均已达到终止状态。运行器重试不会再次发送事件。此组织级生命周期事件仅发送至组织范围端点，不发送至智能体范围端点。非阻塞。

```json
{
  "data": {
    "campaign_id": "3f6b2c9e-2a0d-4c63-b6d6-a708dc98f403",
    "name": "May win-back",
    "agent_id": 12,
    "status": "completed",
    "started_at": "2026-04-20T17:00:00Z",
    "completed_at": "2026-04-20T18:25:11Z",
    "counts": {
      "contacts_total": 150,
      "completed": 121,
      "failed": 11,
      "no_answer": 18,
      "remaining": 0
    }
  },
  "event_id": "8d8f52ce-6b46-423f-9dde-cea0b91ec135",
  "type": "campaign.completed"
}
```

四个结果计数互不重叠，且总和为 `contacts_total`：
`completed` 包含成功联系的联系人；`no_answer` 包含最终结果为无人接听的终止失败／已耗尽联系人；`failed` 包含所有其他终止失败／已耗尽联系人；`remaining` 包含待处理、已排期或正在呼叫的联系人。等待重试的联系人属于 `remaining`，即使其最近一次尝试为无人接听。进行中的通话会在一次性完成快照前完成协调。`started_at` 是配置的营销活动开始时间；未配置开始时间时，则为营销活动创建时间。

### `issue.reported`

当创建[问题报告](/api-reference/issue-reports)时发送——
可以是用户从控制台提交（`source: "user"`），也可以是通话评分自动创建（`source: "system"`）。非阻塞。

```json
{
  "data": {
    "call_id": 987654321,
    "issue_report": {
      "created_at": "2026-04-20T18:25:11.002Z",
      "description": "Five-second silence before responding to the main question.",
      "id": 4321,
      "severity": "warning",
      "source": "system",
      "status": "open",
      "title": "Agent paused too long"
    }
  },
  "event_id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
  "type": "issue.reported"
}
```

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 已分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 已分配智能体时，处理该通话的智能体 |
| `issue_report.severity` | string | `critical`、`warning` 或 `info` |
| `issue_report.status` | string | `open` 或 `resolved` |
| `issue_report.source` | string | `user`（从控制台提交）或 `system`（由评分创建） |

<Note>
  重新评分通话会重建其系统生成的问题报告，从而为重新创建的报告再次发送 `issue.reported`。如果您只希望每个基础问题收到一条通知，请按 `call_id` + `title` 去重。
</Note>

### `issue.escalated`

当问题模式被发送至 ThunderPhone 供工作人员审核时发送：在点击
**上报至 ThunderPhone** 后，或当使用 AI 修复无法确认客户侧修复并自动路由该问题时。仅组织范围端点会接收此事件。

```json
{
  "data": {
    "automatic": false,
    "cluster_id": "7ac2844c-2df0-4fa8-a560-7378da649e19",
    "escalation_id": "ec99f52b-c8c0-41dd-a4f2-dd8a07b10894",
    "status": "open"
  },
  "event_id": "d8f8f420-7a42-45ba-bcf1-b747f9bbecda",
  "type": "issue.escalated"
}
```

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `automatic` | boolean | 自动升级时为 `true`；手动升级时为 `false` |
| `cluster_id` | UUID | 已升级的问题模式 |
| `escalation_id` | UUID | 升级记录 |
| `status` | string | 发送事件时为 `open` |

这是通知，不是证据包。请使用 `cluster_id` 将其与问题模式关联。请参阅[上报至 ThunderPhone](/zh/guides/issues)。

---

## 测试通话事件

### `test-call.completed`

当一次
[测试通话运行](/api-reference/test-calls#test-call-run-object)
达到终态——`completed` 或 `failed` 时发送，包括启动时失败且从未发起通话的运行。非阻塞。适用于将批量 CI 运行接入您的聊天/通知系统。

```json
{
  "data": {
    "test_call_run": {
      "call_id": 987654321,
      "completed_at": "2026-04-20T18:25:04.822Z",
      "error_message": "",
      "id": 7110,
      "status": "completed",
      "target_id": 12,
      "target_type": "agent"
    }
  },
  "event_id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
  "type": "test-call.completed"
}
```

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `agent_id` | integer \| null | 分配智能体时，处理该通话的智能体 |
| `agent_name` | string \| null | 分配智能体时，处理该通话的智能体 |
| `test_call_run.target_type` | string | `agent` 或 `phone_number` |
| `test_call_run.target_id` | integer | 运行目标的智能体 ID 或电话号码 ID，与 `target_type` 对应 |
| `test_call_run.status` | string | `completed` 或 `failed` |
| `test_call_run.call_id` | integer \| null | 运行在发起通话前失败时为 `null` |
| `test_call_run.error_message` | string | 成功时为空 |

---

## 告警事件

### `alert.triggered`

启用了 **发送到开发者 Webhook** 渠道的[告警规则](/zh/guides/alerts)超过其阈值时发送。非阻塞。规则触发一次后会遵循其冷却时间，因此持续超限会在每个冷却窗口内产生一个事件。

```json
{
  "data": {
    "comparator": "lt",
    "event_id": "b8e6a1d4-2c3f-4a5b-9c8d-7e6f5a4b3c2d",
    "fired_at": "2026-04-20T18:00:00+00:00",
    "metric": "success_rate",
    "metric_value": 71.4,
    "rule_id": "d2c3b4a5-6f7e-4d8c-9b0a-1c2d3e4f5a6b",
    "rule_name": "Success rate below 80%",
    "threshold": 80.0,
    "window_hours": 24
  },
  "event_id": "4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f7a",
  "type": "alert.triggered"
}
```

| 字段 | 类型 | 说明 |
|-------|------|-------------|
| `event_id`（位于 `data` 中） | UUID | 告警**触发** ID——不同于封装的投递 `event_id` |
| `rule_id`, `rule_name` | UUID, string | 已触发的规则 |
| `metric` | string | `success_rate`、`failure_rate`、`avg_score`、`call_volume` 或 `suite_regression` |
| `comparator` | string | `lt`、`lte`、`gt` 或 `gte` |
| `metric_value` | number | 规则触发时该指标在窗口内的值 |
| `threshold` | number | 配置的阈值 |
| `window_hours` | integer | 滚动评估窗口 |
| `fired_at` | timestamp | |

有关创建规则、指标、冷却时间以及电子邮件 / Slack 渠道的信息，请参阅[告警指南](/zh/guides/alerts)。

---

## 迁移事件

### `migration.call.complete`

当通过
[`POST /v1/migrations/{id}/calls`](/api-reference/migration-calls) 发起的通话结束时发送，无论由哪个平台承接。非阻塞。将在通话结束后约 5 分钟内送达。`data` 包含
[`telephony.complete`](/zh/webhooks/call-complete) 的所有字段以及一个 `migration` 区块。ThunderPhone 发起的通话也会像往常一样发送 `telephony.complete`，且使用相同的 `call_id`。如果其他平台上的通话在 2 小时后仍未结束，或者其迁移已完成或先丢失密钥，则会以 `status: "unknown"` 发送，且不含转录内容。

```json
{
  "data": {
    "agent_id": 42,
    "agent_name": "Front desk",
    "billable_minutes": null,
    "billing_total_cents": null,
    "call_id": null,
    "direction": "outbound",
    "duration_seconds": 94,
    "end_reason": "user_hangup",
    "end_time": "2026-10-06T17:01:34+00:00",
    "extracted_data": null,
    "from_number": "+15551234567",
    "migration": {
      "arm": "vendor",
      "id": "5f0c2a9e-7b1d-4c3e-8a6f-2d9e1b4c7a30",
      "metadata": {
        "lead_id": "8812"
      },
      "routing_id": "9b2f8c1e-4d3a-4f6b-8e2d-1a7c5b9e0f34",
      "vendor": "retell",
      "vendor_call_id": "call_6a1f0e",
      "vendor_cost_usd": "0.1240"
    },
    "product": "",
    "recording_mode": "vendor",
    "recording_url": "https://…",
    "start_time": "2026-10-06T17:00:00+00:00",
    "status": "completed",
    "summary": "The callee booked a table for two on Thursday.",
    "thunderphone_retained_call_content": true,
    "to_number": "+14155552671",
    "transcripts": [
      {
        "content": "Hi Ada, this is Rosa's calling about your booking.",
        "role": "agent"
      },
      {
        "content": "Yes, Thursday works.",
        "role": "user"
      }
    ],
    "transfer_number": null,
    "unresolved_variables": [],
    "variables": {
      "first_name": "Ada"
    },
    "voice": ""
  },
  "event_id": "7c1e2f3a-4b5c-4d6e-8f7a-9b0c1d2e3f4a",
  "type": "migration.call.complete"
}
```

| 字段 | 类型 | 描述 |
|-------|------|-------------|
| `migration.id` | UUID | 迁移 |
| `migration.routing_id` | UUID | 路由后的通话，即您发起通话时返回的通话 |
| `migration.arm` | string | `ours`（由 ThunderPhone 发起）或 `vendor`（由其他平台发起） |
| `migration.vendor` | string | `retell`、`vapi`、`elevenlabs` 或 `bland` |
| `migration.vendor_call_id` | string \| null | 其他平台的通话 ID；对于 `ours` 为 `null` |
| `migration.metadata` | object | 您发起通话时发送的 `metadata` |
| `migration.vendor_cost_usd` | string \| null | 其他平台报告的通话费用（如有） |
| `call_id` | integer \| null | ThunderPhone 通话 ID；对于 `vendor` 为 `null` |
| `status` | string | 对于 `vendor`：被叫方通话时为 `completed`，未通话时为 `failed`，如上所述时为 `unknown`。对于 `ours`：与 `telephony.complete` 中相同 |

对于 `vendor` 通话，ThunderPhone 没有计费或提取数据：
`billable_minutes`、`billing_total_cents` 和 `extracted_data` 为 `null`，
`product` 和 `voice` 为空，`recording_mode` 为 `vendor`，而
`recording_url` 为其他平台提供的链接（如有）。

### `migration.rollback`

当迁移的渐进式切换自行将所有通话切回另一个平台时发送：15
分钟内有 3 通电话未能连接到 ThunderPhone、发送至 ThunderPhone 的 2 通电话在智能体应答前结束，或
ThunderPhone 的任务结果率低于另一个平台的任务结果率，且差距超过配置的阈值。非阻塞，每次回滚发送一次。此后，ThunderPhone 的
通话占比为 0%，迁移将暂停，直到有人在智能体的“迁移”标签页中恢复迁移。载荷不包含电话号码、转录文本或通话 ID。

```json
{
  "data": {
    "agent_id": 42,
    "agent_name": "Front desk",
    "dropped": 0,
    "migration_id": "5f0c2a9e-7b1d-4c3e-8a6f-2d9e1b4c7a30",
    "ours": {
      "graded": 20,
      "success_rate": 0.8
    },
    "ours_failed": 3,
    "ours_percent": 0,
    "previous_percent": 25,
    "reason": "ours_failed_burst",
    "rolled_back_at": "2026-10-10T12:05:00+00:00",
    "step": 1,
    "theirs": {
      "graded": 20,
      "success_rate": 0.8
    },
    "vendor": "retell"
  },
  "event_id": "3d1f6b2a-8c4e-5a7b-9d0e-2f1a3b4c5d6e",
  "type": "migration.rollback"
}
```

| 字段 | 类型 | 描述 |
|-------|------|-------------|
| `migration_id` | UUID | 迁移 |
| `vendor` | string | `retell`、`vapi`、`elevenlabs` 或 `bland` |
| `reason` | string | `ours_failed_burst`（15 分钟内 3 次连接失败）、`dropped_calls`（30 分钟内有 2 通电话在智能体应答前结束）或 `rate_gap`（双方各至少有 `rollback_min_calls` 通已评分通话时，任务结果率差距超过阈值） |
| `previous_percent` | integer | 回滚前 ThunderPhone 的通话占比 |
| `ours_percent` | integer | 始终为 `0` |
| `step` | integer \| null | 所处的排期步骤（从 0 开始） |
| `ours` / `theirs` | object \| null | 当前步骤中的已评分通话及其成功率；当该步骤的通话数量不足时，`theirs` 可能为最近 30 天的数据。没有数据时为 `null` |
| `ours_failed` | integer | 最近 15 分钟内计入的连接失败次数 |
| `dropped` | integer | 最近 30 分钟内计为中断的通话数量 |
| `rolled_back_at` | timestamp | |

---

## 相关内容

<CardGroup cols={2}>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/zh/webhooks/call-incoming">
    您必须响应的阻塞式入站通话负载。
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone-slash" href="/zh/webhooks/call-complete">
    通话后的转录文本和指标。
  </Card>
  <Card title="Webhook 端点" icon="bolt" href="/zh/webhooks/endpoints">
    将 URL 订阅到这些事件的一个子集。
  </Card>
  <Card title="函数工具" icon="screwdriver-wrench" href="/zh/tools/overview">
    `telephony.tool` / `web.tool` 事件的生成方式。
  </Card>
</CardGroup>
