---
title: "Danh mục sự kiện"
description: "Tất cả loại sự kiện webhook mà ThunderPhone phát ra."
---

Mọi nội dung webhook đều có trường `type` với giá trị là một trong các loại sự kiện trên trang này. Khi bạn đăng ký một [endpoint](/vi/webhooks/endpoints), mảng `events` phải chứa các loại sự kiện bạn muốn nhận (hoặc để trống để đăng ký mọi sự kiện — ngoại trừ các sự kiện theo từng lượt [`telephony.turn`](#telephony-turn) / [`web.turn`](#web-turn), chỉ được gửi đến các endpoint nêu rõ chúng).

Hai kiểu gửi mang các sự kiện này:

* Các lần gửi **Endpoint** luôn là thông báo **không chặn** có [cơ chế thử lại](/vi/webhooks/overview): phản hồi bằng bất kỳ mã 2xx nào; envelope chứa `event_id` để khử trùng lặp.
* Các trao đổi **chặn** chỉ chạy trên [webhook URL đơn kiểu cũ](/vi/webhooks/overview): yêu cầu cấu hình [`telephony.incoming` / `web.incoming`](/vi/webhooks/call-incoming) (số ở chế độ webhook: 13 giây, bao gồm một lần thử lại; khóa widget ở chế độ webhook: 10 giây) và [điều phối công cụ](/vi/tools/overview) ở chế độ webhook. Phản hồi của bạn định hình cuộc gọi trực tiếp.

Các payload ví dụ bên dưới hiển thị envelope endpoint theo thứ tự trên wire (các khóa được sắp xếp theo thứ tự bảng chữ cái: `data`, `event_id`, `type`); các lần gửi cũ mang cùng `data` nhưng không có `event_id`.

## Sự kiện cuộc gọi

### `telephony.incoming`

Được gửi khi một cuộc gọi đến một trong các
[số điện thoại](/api-reference/phone-numbers) của bạn. Việc gửi đến endpoint là
thông báo gửi đi không chờ phản hồi cho **mọi** cuộc gọi đến, dù
số đó được cấu hình tác nhân AI hay cấu hình webhook. Các số không có
tác nhân AI được chỉ định sẽ nhận thêm yêu cầu cấu hình **chặn**
trên webhook cũ — xem
[`telephony.incoming` / `web.incoming`](/vi/webhooks/call-incoming) để biết
đầy đủ schema yêu cầu / phản hồi.

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

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |

### `telephony.complete`

Được gửi khi một cuộc gọi viễn thông đến hoặc đi kết thúc. Không chặn.
Bao gồm bản chép lời, URL bản ghi khi có và tóm tắt thanh toán. Xem
[`telephony.complete` / `web.complete`](/vi/webhooks/call-complete) để biết
schema payload.

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |

### `telephony.tool`

Được gửi sau khi một cuộc gọi viễn thông gọi một
[công cụ hàm](/vi/tools/overview). Đây là thông báo kiểm tra không chặn —
công cụ đã được thực thi khi sự kiện này được gửi; sự kiện bao gồm
các công cụ hàm của riêng bạn và công cụ tích hợp sẵn `send_sms` (không bao gồm công cụ tích hợp sẵn khác,
cơ sở kiến thức, kết nối ứng dụng hoặc công cụ MCP). Với `send_sms`,
cả `arguments.to` và `arguments.body` đều là `[REDACTED]`. Bản chép lời
khi hoàn tất cũng ẩn chúng; truy xuất nội dung và người nhận từ tài nguyên SMS
theo phạm vi tổ chức bằng `message_id` trong phản hồi.

```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` là kết quả đã thực thi: `{"status": <http status>,
"response": <your endpoint's JSON>}` khi thành công, hoặc
`{"status": <status>, "error": "<message>"}` khi thất bại.

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |

### `telephony.turn`

Được gửi trong khi cuộc gọi viễn thông **đang diễn ra**, một lần cho mỗi
lượt có lời nói ngay khi lượt đó xảy ra — phần trả lời được nói của
tác nhân AI và lượt của người gọi được chép lời. Cho phép bạn theo dõi cuộc trò chuyện
trực tiếp qua webhook đơn thuần thay vì thăm dò
[`GET /v1/calls/{call_id}/transcript`](/api-reference/calls#get-transcript).
Không chặn.

<Note>
  **Yêu cầu đăng ký rõ ràng.** Không giống mọi loại sự kiện khác,
  sự kiện lượt không bao giờ được gửi qua mảng `events` trống
  (đăng ký tất cả). Endpoint chỉ nhận chúng khi danh sách `events`
  chứa rõ ràng `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"
}
```

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |
| `position` | integer | Chỉ mục của lượt trong lịch sử cuộc gọi — danh tính ổn định để sắp xếp |
| `role` | string | `assistant` (lời nói của tác nhân AI) hoặc `user` (lời nói của người gọi) |
| `text` | string | Văn bản chép lời của lượt tại thời điểm phát sự kiện |
| `entry_type` | string | Loại mục lịch sử cơ bản: `completion` (tác nhân AI), hoặc `user_turn` / `span` (người gọi) |
| `start_ms`, `end_ms` | integer | Độ lệch âm thanh tính bằng ms kể từ khi cuộc gọi bắt đầu; chỉ xuất hiện khi thời điểm phát âm đã được biết tại thời điểm phát sự kiện |

<Note>
  Việc gửi có ngữ nghĩa ít nhất một lần và các lượt có thể đến **không theo thứ tự**:
  khử trùng lặp theo `event_id` của phong bì và sắp xếp theo `position`. Bản chép lời
  của người gọi vẫn có thể được tinh chỉnh sau khi phát sự kiện; bản chép lời
  [`telephony.complete`](/vi/webhooks/call-complete) sau cuộc gọi là
  nguồn xác thực. Chỉ lượt được nói mới được phát — lệnh gọi công cụ, thì thầm và
  các mục nội bộ khác không bao giờ xuất hiện trong luồng này.
</Note>

### `web.incoming`

Tương đương trên kênh web của `telephony.incoming`, được gửi khi một phiên
[widget web](/vi/widget/overview) hoặc cuộc gọi kiểm tra mic trong trình tạo
bắt đầu. Việc gửi đến endpoint là gửi đi không chờ phản hồi cho mọi phiên web.
Khóa có thể công khai ở `mode="webhook"` sẽ nhận thêm yêu cầu cấu hình
**chặn** trên webhook cũ — yêu cầu chặn đó có cấu trúc khác (`origin_domain`,
`publishable_key_prefix`; không có số điện thoại). Xem
[`telephony.incoming` / `web.incoming`](/vi/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` luôn là chuỗi ký tự `"web"`. Với phiên widget ở chế độ webhook,
`to_number` trống (số tác nhân AI của phiên được chỉ định sau khi cấu hình);
với cuộc gọi kiểm tra mic trong trình tạo, `origin_domain` và
`publishable_key_prefix` trống.

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |

### `web.complete`

Tương đương trên kênh web của `telephony.complete`, bao gồm cuộc gọi widget
web (`direction: "web"`) và cuộc gọi kiểm tra mic trong trình tạo
(`direction: "test"`). Không chặn. Có cùng cấu trúc payload với
[`telephony.complete`](/vi/webhooks/call-complete), cộng thêm `origin_domain`,
với `from_number` được đặt thành `"web"`.

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |

<Note>
  Trên webhook cũ có một URL duy nhất, các cuộc gọi kiểm tra mic trong trình tạo
  theo lịch sử được báo cáo là `telephony.complete` — chỉ các cuộc gọi có `direction:
  "web"` mới sử dụng loại `web.complete` tại đó. Hệ thống endpoint
  ánh xạ cả cuộc gọi web và cuộc gọi kiểm tra thành `web.*`. Payload lịch sử có thể
  chứa các giá trị `direction` cũ là `widget` hoặc `mic`.
</Note>

### `web.tool`

Tương đương trên kênh web của `telephony.tool`. `data` chứa
`origin_domain` thay cho `from_number` / `to_number`.

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |

### `web.turn`

Tương đương trên kênh web của [`telephony.turn`](#telephony-turn),
bao gồm cuộc gọi widget web và cuộc gọi kiểm tra mic trong trình tạo. Có cùng cấu trúc
payload, với `origin_domain` thay cho `from_number` / `to_number`.
Giống `telephony.turn`, sự kiện này yêu cầu **đăng ký rõ ràng** —
không bao giờ được gửi qua mảng `events` trống.

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, nếu có tác nhân AI được chỉ định |

### `call.transfer_completed`

Được gửi một lần cho mỗi cuộc gọi cùng kết quả cuối cùng của
[chuyển cuộc gọi](/vi/guides/call-transfers): chuyển lạnh hoặc cầu nối giữa hai người
mà chuyển ấm để lại sau khi tác nhân AI rời cuộc gọi.
Không chặn và chỉ được gửi đến endpoint (không bao giờ đến webhook
một URL cũ). Sự kiện đến sau `telephony.complete` của cuộc gọi:
khi nhà cung cấp tiếp nhận cuộc gọi hoặc việc chuyển thất bại, hoặc khi
ThunderPhone tạo cầu nối cho cuộc gọi, sau khi cầu nối kết thúc.

```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"
}
```

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `call_id` | integer | Cuộc gọi đã được chuyển |
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, khi được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, khi được chỉ định |
| `transfer_outcome` | string | `refer_accepted`: nhà cung cấp đã tiếp nhận cuộc gọi. `bridged`: ThunderPhone tự duy trì kết nối giữa người gọi và đích đến, do nhà cung cấp từ chối chuyển lạnh hoặc do tác nhân AI của chuyển ấm rời cuộc gọi. `bridge_unanswered`: nhà cung cấp từ chối chuyển lạnh và đích đến không trả lời cuộc gọi do ThunderPhone thực hiện. `failed`: việc chuyển không thành công và cuộc gọi đã kết thúc |
| `destination` | string \| null | Số điện thoại mà cuộc gọi được chuyển đến |
| `sip_status` | integer \| null | Trạng thái SIP của nhà cung cấp khi từ chối chuyển lạnh: `403` (ví dụ: trunk Twilio không hỗ trợ chuyển cuộc gọi), `405` hoặc `501`. `null` khi nhà cung cấp không từ chối |
| `bridge_kind` | string \| null | Chỉ khi `bridged`: `cold_fallback` (chuyển lạnh bị từ chối mà ThunderPhone đã kết nối) hoặc `warm` (hai người trong chuyển ấm sau khi tác nhân AI rời cuộc gọi) |
| `bridge_seconds` | integer \| null | Chỉ khi `bridged`: thời lượng cầu nối mà ThunderPhone tính phí, tính bằng giây |
| `bridge_total_cents` | integer \| null | Chỉ khi `bridged`: chi phí cầu nối tính bằng xu USD sau khi áp dụng mọi tín dụng cuộc gọi miễn phí, được tính phí riêng với `billing_total_cents` của cuộc gọi |

Các giá trị tương tự cũng có trên [đối tượng cuộc gọi](/api-reference/calls#call-object)
dưới dạng `transfer_outcome`, `transfer_destination`, `transfer_sip_status`,
`transfer_bridge_kind`, `transfer_bridge_seconds` và
`transfer_bridge_total_cents`. `event_id` giống nhau trên mọi lần gửi
cho một cuộc gọi, vì vậy báo cáo lặp lại không bao giờ tạo sự kiện thứ hai.

---

## Sự kiện SMS

Sự kiện SMS mô tả tin nhắn được gửi qua tài khoản Twilio hoặc Telnyx đã kết nối
của tổ chức. Nội dung tin nhắn được lược bỏ và `to` được che giấu.
Truy xuất tin nhắn trong phạm vi tổ chức từ
[`GET /v1/sms/{message_id}`](/api-reference/sms#retrieve-a-message) khi cần
nội dung hoặc người nhận.

### `sms.sent`

Được gửi khi nhà mạng của khách hàng chấp nhận yêu cầu gửi SMS. Đây không phải
biên nhận đã gửi đến thiết bị.

```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`

Được gửi sau khi nhà mạng từ chối vĩnh viễn, sau khi đã hết lượt thử lại tạm
thời hoặc khi kết quả không xác định một cách cuối cùng. `error_code` là mã
ThunderPhone ổn định và `error_message` nêu hành động khách hàng cần thực hiện
khi có. `status: "unknown"` nghĩa là nhà mạng có thể đã chấp nhận SMS; hãy đối
chiếu trong nhật ký nhà mạng vì ThunderPhone sẽ không tự động gửi lại.

### `sms.received`

Dành riêng cho hỗ trợ SMS đến. Không có sự kiện `sms.received` nào được phát
ra trong bản phát hành hiện tại. Cấu hình webhook nhà mạng cho SMS đến và xác
minh chữ ký sẽ được phát hành riêng.

---

## Sự kiện giọng nói

Việc tạo giọng nói tùy chỉnh diễn ra không đồng bộ. Các sự kiện không chặn này
cho phép bạn phản ứng với kết quả cuối cùng thay vì thăm dò
[điểm cuối thông tin chi tiết bản sao](/api-reference/custom-voices#list-and-retrieve-clones).

`voice.ready` và `voice.failed` chỉ được gửi đến điểm cuối toàn tổ chức có
`events: []`. Không thể chọn chúng làm bộ lọc sự kiện rõ ràng.

### `voice.ready`

Được gửi khi giọng nói tùy chỉnh hoàn tất xử lý và có thể được gán cho một
tác nhân AI.

```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`

Được gửi khi quá trình xử lý giọng nói tùy chỉnh gặp lỗi vĩnh viễn.

```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"
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `voice.id` | string | ID công khai của giọng nói tùy chỉnh |
| `voice.name` | string | Giá trị giọng nói của tác nhân AI theo dạng `custom:<public_id>` |
| `voice.display_name` | string | Tên giọng nói hiển thị cho tổ chức |
| `voice.language` | string | Mã ngôn ngữ duy nhất của bản sao |
| `voice.gender` | string | `male`, `female` hoặc chuỗi rỗng |
| `voice.status` | string | `ready` cho `voice.ready`; `failed` cho `voice.failed` |
| `voice.failure_reason` | string | Rỗng khi thành công; chi tiết lỗi xử lý khi thất bại |
| `voice.created_at`, `voice.updated_at` | timestamp | Dấu thời gian ISO 8601 |
| `reason` | string | Chi tiết lỗi; chỉ có trên `voice.failed` |

---

## Sự kiện chất lượng

### `call.graded`

Được gửi mỗi khi một lần [chấm điểm cuộc gọi bằng AI](/api-reference/calls#ai-call-grading)
hoàn tất cho một cuộc gọi. Không chặn.

```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"
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, khi được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, khi được chỉ định |
| `grade.id` | integer | ID đánh giá |
| `grade.score` | integer \| null | 0–100 |
| `grade.call_outcome` | string | `success`, `failure`, `unknown` hoặc `no_conversation` |
| `grade.summary` | string | Tóm tắt một đoạn |
| `grade.detected_issues` | array | Chuỗi mô tả vấn đề do trình chấm điểm phát hiện |
| `grade.status` | string | Luôn là `completed` — chỉ các lượt chạy đã hoàn tất mới phát sự kiện |
| `grade.grader_model` | string | Trình chấm điểm tạo ra kết quả (ví dụ: `heuristic-v1`) |
| `grade.graded_at`, `grade.created_at` | timestamp | |
| `report` | object \| null | [Báo cáo cuộc gọi](/api-reference/calls#call-report) dành cho khách hàng: nhãn kết quả, cờ cần chú ý và lý do, người gọi, tóm tắt một dòng, trải nghiệm của người gọi. Ở lượt đánh giá heuristic sớm, giá trị này là `null` hoặc báo cáo `pending` có các trường là giá trị giữ chỗ; sự kiện của lượt đánh giá đầy đủ sẽ chứa báo cáo đã hoàn tất |

<Note>
  Một cuộc gọi có thể được chấm điểm nhiều lần — điểm heuristic nhanh thường
  được theo sau bởi điểm từ mô hình đầy đủ sau khi bản ghi âm khả dụng, và
  bạn cũng có thể chấm điểm lại thủ công. Mỗi lần chạy hoàn tất gửi sự kiện
  `call.graded` riêng; xem `graded_at` mới nhất là nguồn xác thực.
</Note>

### `call.data_extracted`

Được gửi mỗi khi quá trình trích xuất dữ liệu có cấu trúc hoàn tất thành công, bao gồm
lần thử lại muộn sau `telephony.complete` / `web.complete` hoặc lần chạy lại thủ công qua
[`POST /v1/calls/{call_id}/extract`](/api-reference/calls#run-data-extraction).
Không chặn.

Ở chế độ trích xuất chặn, sự kiện hoàn tất thông thường chờ không quá
ngân sách trích xuất 75 giây. Nếu tiến trình worker trích xuất bị mất, quy trình
xử lý hoàn tất trong môi trường production (mỗi năm phút) sẽ giải phóng một
sự kiện hoàn tất có `blocking_deadline_at` đã qua trước khi bắt đầu một lần
thử trích xuất khác. Thành công muộn hơn được gửi riêng dưới dạng sự kiện này.

<Warning>
  Giá trị được trích xuất là cách mô hình diễn giải cuộc hội thoại. Mỗi giá trị
  khác null bao gồm câu trích dẫn, vai trò người nói và chỉ mục lượt nói làm
  cơ sở, cùng cờ xác minh ở cấp lần chạy. Xác minh kết quả trước khi đưa ra
  quyết định liên quan đến tiền, danh tính hoặc quyền truy cập.
</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"
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân đã xử lý cuộc gọi, nếu có tác nhân được chỉ định |
| `agent_name` | string \| null | Tác nhân đã xử lý cuộc gọi, nếu có tác nhân được chỉ định |
| `summary` | string \| null | [Bản tóm tắt cuộc gọi](/vi/webhooks/call-complete) đã hoàn tất khi tác nhân bật **Tạo bản tóm tắt cuộc gọi**, vì vậy một sự kiện trích xuất muộn cũng gửi bản tóm tắt đã bỏ lỡ thời hạn hoàn tất; nếu không thì là `null`. Tác nhân có bản tóm tắt nhưng không có trường trích xuất sẽ không bao giờ gửi sự kiện này: đọc bản tóm tắt muộn từ `GET /v1/calls/{call_id}` |
| `extracted_data.status` | string | Luôn là `completed` cho sự kiện này |
| `extracted_data.fields` | object | Giá trị được khóa theo các khóa trường trích xuất đã cấu hình; giá trị không khả dụng là `null` |
| `extracted_data.evidence` | object | Bằng chứng được khóa theo trường trích xuất. Giá trị khác null có câu trích dẫn chính xác đã được kiểm tra cấu trúc (tối đa 1.000 ký tự), `speaker_role` (`caller` hoặc `agent`) và `turn_index`; các câu trích dẫn dài hơn do mô hình trả về bị từ chối thay vì cắt ngắn, và bằng chứng là `null` bất cứ khi nào trường tương ứng là `null` |
| `extracted_data.verification` | string | Chỉ là `verified` khi lượt kiểm tra bằng chứng độc lập trả về chính xác một kết luận hợp lệ cho mọi trường ứng viên. `unavailable` nghĩa là lượt kiểm tra thất bại, hết thời gian, không đủ ngân sách hoặc trả về đầu ra bị lỗi định dạng hay không đầy đủ. Một lượt kiểm tra hoàn toàn không khả dụng vẫn giữ các giá trị có cơ sở cấu trúc để khách hàng xem xét. Với đầu ra một phần, các kết luận hợp lệ được áp dụng và từng ứng viên không có chính xác một kết luận hợp lệ sẽ bị đặt thành null |
| `extracted_data.field_reasons` | object | Lý do được khóa theo các trường bị đặt thành null bởi cơ sở cấu trúc hoặc trình xác minh độc lập |
| `extracted_data.schema_version` | string | Hash của schema trường chính xác được dùng cho lần trích xuất này |
| `extracted_at` | timestamp | Thời điểm hoàn tất theo ISO 8601 |
| `model` | string | Mô hình được dùng để trích xuất |

### `campaign.completed`

Được gửi một lần khi chiến dịch chuyển từ `running` sang `completed`, dù
lịch chạy kết thúc hay mọi liên hệ đã đạt trạng thái cuối. Các lần thử lại của runner
không gửi thêm sự kiện. Sự kiện vòng đời cấp tổ chức này chỉ được gửi đến
endpoint phạm vi tổ chức, không gửi đến endpoint phạm vi tác nhân. Không chặn.

```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"
}
```

Bốn số lượng kết quả không chồng lấp và tổng bằng `contacts_total`:
`completed` chứa các liên hệ thành công; `no_answer` chứa các liên hệ
thất bại/đã hết lượt thử ở trạng thái cuối là không trả lời; `failed` chứa
mọi liên hệ thất bại/đã hết lượt thử ở trạng thái cuối khác; và `remaining`
chứa các liên hệ đang chờ, đã lên lịch hoặc hiện đang gọi. Một liên hệ đang
chờ thử lại là `remaining`, kể cả khi lần thử gần nhất không được trả lời.
Các cuộc gọi đang diễn ra được đối soát trước ảnh chụp hoàn tất chỉ diễn ra
một lần. `started_at` là thời điểm bắt đầu chiến dịch đã cấu hình, hoặc thời
điểm tạo chiến dịch khi chưa cấu hình thời điểm bắt đầu.

### `issue.reported`

Được gửi khi một [báo cáo vấn đề](/api-reference/issue-reports) được tạo —
do người dùng gửi từ dashboard (`source: "user"`) hoặc được tạo tự động
bằng tính năng chấm điểm cuộc gọi (`source: "system"`). Không chặn.

```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"
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân đã xử lý cuộc gọi, nếu có tác nhân được chỉ định |
| `agent_name` | string \| null | Tác nhân đã xử lý cuộc gọi, nếu có tác nhân được chỉ định |
| `issue_report.severity` | string | `critical`, `warning` hoặc `info` |
| `issue_report.status` | string | `open` hoặc `resolved` |
| `issue_report.source` | string | `user` (được gửi từ dashboard) hoặc `system` (được tạo bởi quá trình chấm điểm) |

<Note>
  Chấm điểm lại một cuộc gọi sẽ xây dựng lại các báo cáo vấn đề do hệ thống
  tạo, đồng thời gửi lại `issue.reported` cho các báo cáo được tạo lại. Khử
  trùng lặp theo `call_id` + `title` nếu bạn chỉ muốn một thông báo cho mỗi
  vấn đề nền tảng.
</Note>

### `issue.escalated`

Được gửi khi một mẫu vấn đề được chuyển đến ThunderPhone để đội ngũ xem xét: sau
khi **Báo cáo cho ThunderPhone**, hoặc khi Khắc phục bằng AI không thể xác nhận
cách khắc phục phía khách hàng và tự động chuyển vấn đề. Chỉ các endpoint
phạm vi toàn tổ chức nhận được sự kiện này.

```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"
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `automatic` | boolean | `true` cho chuyển cấp tự động; `false` cho chuyển cấp thủ công |
| `cluster_id` | UUID | Mẫu vấn đề đã được chuyển cấp |
| `escalation_id` | UUID | Bản ghi chuyển cấp |
| `status` | string | `open` khi sự kiện được gửi |

Đây là thông báo, không phải gói bằng chứng. Dùng `cluster_id` để liên kết
với mẫu vấn đề. Xem [Báo cáo cho ThunderPhone](/vi/guides/issues).

---

## Sự kiện cuộc gọi kiểm thử

### `test-call.completed`

Được gửi khi một
[lần chạy cuộc gọi kiểm thử](/api-reference/test-calls#test-call-run-object)
đạt trạng thái kết thúc — `completed` hoặc `failed`, bao gồm cả các lần chạy
thất bại khi khởi chạy và không bao giờ tạo cuộc gọi. Không chặn. Hữu ích
để kết nối các lần chạy CI hàng loạt với hệ thống chat/thông báo của bạn.

```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"
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `agent_id` | integer \| null | Tác nhân AI đã xử lý cuộc gọi, nếu được chỉ định |
| `agent_name` | string \| null | Tác nhân AI đã xử lý cuộc gọi, nếu được chỉ định |
| `test_call_run.target_type` | string | `agent` hoặc `phone_number` |
| `test_call_run.target_id` | integer | Id tác nhân AI hoặc id số điện thoại mà lần chạy nhắm đến, khớp với `target_type` |
| `test_call_run.status` | string | `completed` hoặc `failed` |
| `test_call_run.call_id` | integer \| null | `null` khi lần chạy thất bại trước khi thực hiện cuộc gọi |
| `test_call_run.error_message` | string | Trống khi thành công |

---

## Sự kiện cảnh báo

### `alert.triggered`

Được gửi khi một [quy tắc cảnh báo](/vi/guides/alerts) có kênh **Gửi đến
webhook dành cho nhà phát triển** được bật vượt qua ngưỡng.
Không chặn. Một quy tắc chỉ kích hoạt một lần rồi tuân theo thời gian chờ,
do đó một vi phạm kéo dài tạo một sự kiện cho mỗi khoảng thời gian chờ.

```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"
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `event_id` (trong `data`) | UUID | Id **kích hoạt** cảnh báo — khác với `event_id` gửi trong phong bì |
| `rule_id`, `rule_name` | UUID, string | Quy tắc đã kích hoạt |
| `metric` | string | `success_rate`, `failure_rate`, `avg_score`, `call_volume` hoặc `suite_regression` |
| `comparator` | string | `lt`, `lte`, `gt` hoặc `gte` |
| `metric_value` | number | Giá trị của chỉ số trong khoảng thời gian khi quy tắc kích hoạt |
| `threshold` | number | Ngưỡng đã cấu hình |
| `window_hours` | integer | Khoảng thời gian đánh giá lùi |
| `fired_at` | timestamp | |

Xem [hướng dẫn Cảnh báo](/vi/guides/alerts) để tạo quy tắc, chỉ số,
thời gian chờ và các kênh email / Slack.

---

## Sự kiện di chuyển

### `migration.call.complete`

Được gửi khi một cuộc gọi được thực hiện qua
[`POST /v1/migrations/{id}/calls`](/api-reference/migration-calls) kết thúc,
bất kể nền tảng nào thực hiện cuộc gọi đó. Không chặn. Sự kiện này đến trong
khoảng tối đa 5 phút sau khi cuộc gọi kết thúc. `data` có mọi trường của
[`telephony.complete`](/vi/webhooks/call-complete) cùng với một khối `migration`.
Một cuộc gọi do ThunderPhone thực hiện cũng gửi `telephony.complete` như
thông thường, với cùng `call_id`. Một cuộc gọi trên nền tảng khác chưa kết thúc
sau 2 giờ, hoặc có quá trình di chuyển đã hoàn tất hoặc mất khóa trước đó, sẽ
được gửi với `status: "unknown"` và không có bản chép lời.

```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"
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `migration.id` | UUID | Quá trình di chuyển |
| `migration.routing_id` | UUID | Cuộc gọi được định tuyến, như được trả về khi bạn thực hiện cuộc gọi |
| `migration.arm` | string | `ours` (ThunderPhone thực hiện cuộc gọi) hoặc `vendor` (nền tảng khác thực hiện) |
| `migration.vendor` | string | `retell`, `vapi`, `elevenlabs` hoặc `bland` |
| `migration.vendor_call_id` | string \| null | ID cuộc gọi của nền tảng khác; `null` đối với `ours` |
| `migration.metadata` | object | `metadata` bạn đã gửi khi thực hiện cuộc gọi |
| `migration.vendor_cost_usd` | string \| null | Chi phí cuộc gọi mà nền tảng khác báo cáo, nếu có |
| `call_id` | integer \| null | ID cuộc gọi ThunderPhone; `null` đối với `vendor` |
| `status` | string | Đối với `vendor`: `completed` khi người được gọi đã nói chuyện, `failed` khi họ không nói chuyện, `unknown` như trên. Đối với `ours`: giống như trong `telephony.complete` |

Đối với cuộc gọi `vendor`, ThunderPhone không có dữ liệu thanh toán hoặc trích
xuất: `billable_minutes`, `billing_total_cents` và `extracted_data` là `null`,
`product` và `voice` để trống, `recording_mode` là `vendor`, và
`recording_url` là liên kết của nền tảng khác, nếu nền tảng đó cung cấp.

### `migration.rollback`

Được gửi khi quá trình chuyển đổi dần của một đợt migration tự động chuyển mọi cuộc gọi trở lại nền tảng còn lại: 3 cuộc gọi không kết nối được với ThunderPhone trong vòng 15 phút, 2 cuộc gọi được gửi đến ThunderPhone kết thúc trước khi tác nhân AI trả lời, hoặc tỷ lệ kết quả tác vụ của ThunderPhone thấp hơn tỷ lệ của nền tảng còn lại vượt quá mức chênh lệch đã cấu hình. Không chặn, một lần cho mỗi lần hoàn tác. Sau đó, tỷ lệ cuộc gọi của ThunderPhone là 0% và migration bị tạm dừng cho đến khi có người tiếp tục nó trong tab Migration của tác nhân AI. Payload không chứa số điện thoại, bản chép lời hoặc ID cuộc gọi.

```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"
}
```

| Trường | Kiểu | Mô tả |
|-------|------|-------------|
| `migration_id` | UUID | Migration |
| `vendor` | string | `retell`, `vapi`, `elevenlabs` hoặc `bland` |
| `reason` | string | `ours_failed_burst` (3 lần kết nối thất bại trong 15 phút), `dropped_calls` (2 cuộc gọi kết thúc trước khi tác nhân AI trả lời, trong vòng 30 phút), hoặc `rate_gap` (chênh lệch tỷ lệ kết quả tác vụ trên ít nhất `rollback_min_calls` cuộc gọi đã đánh giá cho mỗi bên) |
| `previous_percent` | integer | Tỷ lệ cuộc gọi của ThunderPhone trước khi hoàn tác |
| `ours_percent` | integer | Luôn là `0` |
| `step` | integer \| null | Bước lịch trình đang áp dụng (đánh số từ 0) |
| `ours` / `theirs` | object \| null | Các cuộc gọi đã đánh giá trong bước hiện tại và tỷ lệ thành công của chúng; `theirs` có thể là dữ liệu 30 ngày gần nhất khi bước có quá ít cuộc gọi. `null` khi không có cuộc gọi nào |
| `ours_failed` | integer | Số lần kết nối thất bại được tính trong 15 phút gần nhất |
| `dropped` | integer | Số cuộc gọi được tính là đã ngắt trong 30 phút gần nhất |
| `rolled_back_at` | timestamp | |

---

## Liên quan

<CardGroup cols={2}>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/vi/webhooks/call-incoming">
    Payload cuộc gọi đến có chặn mà bạn phải phản hồi.
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone-slash" href="/vi/webhooks/call-complete">
    Bản chép lời và chỉ số sau cuộc gọi.
  </Card>
  <Card title="Điểm cuối webhook" icon="bolt" href="/vi/webhooks/endpoints">
    Đăng ký một URL với một tập hợp con các sự kiện này.
  </Card>
  <Card title="Công cụ hàm" icon="screwdriver-wrench" href="/vi/tools/overview">
    Cách các sự kiện `telephony.tool` / `web.tool` được tạo.
  </Card>
</CardGroup>
