---
title: "Điểm cuối webhook"
description: "Quản lý nhiều URL webhook với secret riêng cho từng điểm cuối và bộ lọc sự kiện."
---

Hệ thống webhook dựa trên endpoint cho phép bạn đăng ký **nhiều**
đích đến cho mỗi tổ chức, mỗi đích có secret riêng, trạng thái riêng
và gói đăng ký riêng cho một tập hợp con các loại sự kiện. Đây là
mô hình được khuyến nghị cho mọi tích hợp mới.

So sánh với [webhook một URL cũ](/api-reference/organizations#legacy-single-url-webhook),
được duy trì để tương thích ngược nhưng chỉ hỗ trợ một URL cho mỗi
tổ chức.

## Endpoint

| Phương thức | Đường dẫn | Vai trò bắt buộc | Mô tả |
|--------|------|---------------|-------------|
| `GET` | `/v1/developer/webhook-endpoints` | `admin+` | Liệt kê endpoint |
| `POST` | `/v1/developer/webhook-endpoints` | `admin+` | Tạo endpoint |
| `PATCH` | `/v1/developer/webhook-endpoints/{endpoint_id}` | `admin+` | Cập nhật nhãn / URL / sự kiện / trạng thái |
| `DELETE` | `/v1/developer/webhook-endpoints/{endpoint_id}` | `admin+` | Xóa endpoint |
| `POST` | `/v1/developer/webhook-endpoints/{endpoint_id}/rotate-secret` | `admin+` | Thay thế secret ký |
| `POST` | `/v1/developer/webhook-endpoints/{endpoint_id}/test` | `admin+` | Gửi lượt phân phối kiểm thử đã ký |
| `GET` | `/v1/developer/webhook-deliveries` | `admin+` | Kiểm tra kết quả phân phối endpoint và phân phối cũ gần đây |

## Đối tượng endpoint

```json
{
  "id": "c4d5e6f7-...",
  "label": "Production — Call events",
  "url": "https://example.com/thunderphone/hook",
  "events": ["telephony.incoming", "telephony.complete"],
  "status": "active",
  "agent_id": 42,
  "agent_name": "Support Agent",
  "secret_hint": "a1b2…9f0e",
  "paused_at": null,
  "pause_last_error": "",
  "pause_undelivered_count": null,
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z"
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `id` | UUID | ID điểm cuối |
| `label` | string | Tên hiển thị, 1–120 ký tự |
| `url` | string | URL HTTPS; cho phép `http://localhost` để phát triển |
| `events` | mảng string | Loại sự kiện đã đăng ký (xem [giá trị hợp lệ](#valid-event-types)). Mảng rỗng đăng ký tất cả sự kiện, ngoại trừ sự kiện theo lượt chỉ yêu cầu đăng ký rõ ràng (`telephony.turn` / `web.turn`) |
| `status` | string | `active`, `disabled` (tạm dừng thủ công) hoặc `failing` (tự động đặt khi một lần gửi dùng hết lịch thử lại 24 giờ mà không nhận được dù chỉ một phản hồi 2xx) |
| `agent_id` | integer \| null | Tác nhân AI mà điểm cuối này áp dụng; `null` nghĩa là áp dụng cho toàn tổ chức |
| `agent_name` | string \| null | Tên của tác nhân AI được áp dụng, hoặc `null` đối với điểm cuối áp dụng cho toàn tổ chức |
| `secret_hint` | string | 4 ký tự đầu và 4 ký tự cuối của secret ký với dấu ba chấm (`a1b2…9f0e`) — đủ để đối chiếu với secret bạn đã lưu cục bộ mà không làm lộ toàn bộ giá trị |
| `paused_at` | timestamp \| null | Thời điểm ThunderPhone đặt điểm cuối thành `failing`. Là `null` khi trạng thái là `active` hoặc `disabled` |
| `pause_last_error` | string | Lỗi gửi gần nhất khi điểm cuối bị tạm dừng, ví dụ `HTTP 503: Service Unavailable`. Trống trừ khi là `failing` |
| `pause_undelivered_count` | integer \| null | Sự kiện chưa được gửi kể từ lần gửi thành công gần nhất của điểm cuối, được đếm khi điểm cuối bị tạm dừng |
| `created_at`, `updated_at` | timestamp | |

<Note>
  `secret` đầy đủ của endpoint chỉ được trả về **một lần** khi tạo và
  không bao giờ được trả lại. Lưu trữ an toàn — nếu bạn làm mất,
  [xoay vòng secret](#rotate-the-signing-secret) để nhận secret mới.
</Note>

### Loại sự kiện hợp lệ

`events` được xác thực theo đúng tập hợp này — các giá trị ngoài danh sách
sẽ trả về `400`. Xem [Danh mục sự kiện](/vi/webhooks/events) để biết cấu trúc
payload của từng loại.

- `telephony.incoming`, `telephony.complete`, `telephony.tool`, `telephony.turn`
- `web.incoming`, `web.complete`, `web.tool`, `web.turn`
- `sms.sent`, `sms.failed`
- `sms.received` (đã dành riêng; chưa được phát ra)
- `call.graded`, `call.data_extracted`, `call.transfer_completed`
- `campaign.completed`
- `issue.reported`, `issue.escalated`
- `test-call.completed`
- `alert.triggered`

`issue.escalated` không có ngữ cảnh tác nhân AI và chỉ được gửi đến các
endpoint trên toàn tổ chức.

Không thể chọn rõ ràng `voice.ready` và `voice.failed`. Để nhận các sự kiện
này, hãy tạo endpoint trên toàn tổ chức với `events: []`. Danh sách sự kiện
trống nhận mọi sự kiện được hỗ trợ, ngoại trừ `telephony.turn` và `web.turn`,
vốn phải được chọn rõ ràng.

### Trạng thái endpoint

- `active` — các lần gửi được thực hiện bình thường.
- `disabled` — được tạm dừng thủ công qua `PATCH`. Không có request nào được gửi. Chúng tôi
  không bao giờ thay đổi trạng thái của endpoint `disabled`; việc chuyển lại về
  `active` luôn do bạn quyết định.
- `failing` — được đặt tự động khi một lần gửi đến endpoint sử dụng hết
  toàn bộ lịch thử lại (8 lần thử trong 24 giờ) mà không từng nhận được mã 2xx. Endpoint ở trạng thái lỗi sẽ không nhận thêm lưu lượng truy cập.
  Chúng tôi gửi email cho chủ sở hữu và quản trị viên của tổ chức bạn khi điều này xảy ra, và
  dashboard hiển thị endpoint đã tạm dừng cùng nút Kích hoạt lại.
  Sau khi endpoint được khắc phục, `PATCH` trạng thái của endpoint về `active`;
  các lần gửi có lịch thử lại chưa hết hạn sẽ tiếp tục từ vị trí đã dừng.

---

## Liệt kê endpoint

<CodeGroup>
```bash cURL
curl https://api.thunderphone.com/v1/developer/webhook-endpoints \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```
</CodeGroup>

Trả về một mảng [đối tượng Endpoint](#endpoint-object).
Truyền `?agent_id=42` để chỉ trả về các endpoint áp dụng cho tác nhân AI đó.

### Endpoint áp dụng cho tác nhân AI

Endpoint trên toàn tổ chức nhận mọi sự kiện khớp. Endpoint có `agent_id` chỉ
nhận các sự kiện khớp cho cuộc gọi do tác nhân AI đó xử lý; các sự kiện không
có ngữ cảnh tác nhân AI, chẳng hạn như `alert.triggered`, sẽ không bao giờ đến
đó. Bạn cũng có thể tạo và quản lý các endpoint này từ mục
**Webhook** của trình xây dựng tác nhân AI.

---

## Tạo endpoint

<CodeGroup>
```bash cURL
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label":  "Production — Call events",
    "url":    "https://example.com/thunderphone/hook",
    "events": ["telephony.incoming", "telephony.complete"]
  }'
```

```python Python
result = requests.post(
    "https://api.thunderphone.com/v1/developer/webhook-endpoints",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
    json={
        "label":  "Production — Call events",
        "url":    "https://example.com/thunderphone/hook",
        "events": ["telephony.incoming", "telephony.complete"],
    },
).json()
secret = result["secret"]
endpoint_id = result["id"]
```
</CodeGroup>

### Trường yêu cầu

| Trường | Loại | Bắt buộc | Mô tả |
|-------|------|----------|-------------|
| `label` | string | có | 1–120 ký tự |
| `url` | string | có | URL HTTPS (`http` chỉ được phép cho `localhost` / `127.0.0.1`) |
| `events` | array | không | Để trống/bỏ qua sẽ đăng ký tất cả sự kiện ngoại trừ `telephony.turn` / `web.turn`, yêu cầu đăng ký rõ ràng. Phải dùng các giá trị được liệt kê trong [Loại sự kiện hợp lệ](#valid-event-types); các giá trị trùng lặp sẽ bị xóa |
| `agent_id` | integer \| null | không | Giới hạn việc gửi đến một tác nhân AI trong tổ chức này; bỏ qua hoặc dùng `null` cho endpoint áp dụng toàn tổ chức |

Trả về `201 Created` cùng [đối tượng Endpoint](#endpoint-object) và một
trường `secret` cấp cao bổ sung chứa khóa ký thô — một chuỗi hex gồm
48 ký tự:

```json
{
  "id": "c4d5e6f7-…",
  "label": "Production — Call events",
  "url": "https://example.com/thunderphone/hook",
  "events": ["telephony.incoming", "telephony.complete"],
  "status": "active",
  "secret_hint": "a1b2…9f0e",
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z",
  "secret": "a1b2c37e08d94f5b16a2c8d90e7f3a4b5c6d7e8f90a19f0e"
}
```

<Warning>
  `secret` được trả về **chỉ khi tạo**. Các phản hồi `GET` tiếp theo
  chỉ bao gồm `secret_hint`. Sao chép toàn bộ giá trị vào trình quản lý
  secret của bạn trước khi đóng phản hồi.
</Warning>

---

## Cập nhật endpoint

<CodeGroup>
```bash cURL
curl -X PATCH https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-... \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label":  "Production — Call + Grade events",
    "events": ["telephony.incoming", "telephony.complete", "call.graded"]
  }'
```
</CodeGroup>

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `label` | string | |
| `url` | string | |
| `events` | array | |
| `status` | string | `active` hoặc `disabled`. Đặt thành `active` để bật lại endpoint mà máy chủ đã đánh dấu là `failing` |
| `agent_id` | integer \| null | Đặt id tác nhân AI để giới hạn endpoint, hoặc `null` để áp dụng cho toàn tổ chức |

Trả về `200 OK` cùng [đối tượng Endpoint](#endpoint-object) đã cập nhật.

---

## Luân chuyển bí mật ký

Thay thế bí mật ký của một điểm cuối, ví dụ khi bí mật bị mất hoặc
có thể đã bị lộ. Với điểm cuối thuộc phạm vi tác nhân AI, bạn cũng có thể sử dụng
bảng điều khiển: mở mục **Webhook** của tác nhân AI và chọn
**Tạo lại bí mật** trên điểm cuối. Các điểm cuối trên toàn tổ chức được
luân chuyển thông qua API.

<CodeGroup>
```bash cURL
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-.../rotate-secret \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```
</CodeGroup>

| Trường | Loại | Bắt buộc | Mô tả |
|-------|------|----------|-------------|
| `include_copies` | logic | không | Mặc định là `true`. Cũng cấp bí mật mới cho các điểm cuối khác trong tổ chức của bạn có cùng URL và cùng bí mật hiện tại, chẳng hạn như bản sao của điểm cuối này trên các tác nhân AI khác, để một bộ nhận vẫn xác minh bằng một bí mật |

Trả về `200 OK`:

```json
{
  "endpoint": { "id": "c4d5e6f7-...", "secret_hint": "7f3a…c21d", "...": "..." },
  "secret": "7f3a90b2c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5c21d",
  "rotated_endpoint_ids": ["c4d5e6f7-..."]
}
```

| Trường | Loại | Mô tả |
|-------|------|-------------|
| `endpoint` | đối tượng | [Đối tượng điểm cuối](#endpoint-object) với `secret_hint` mới |
| `secret` | chuỗi | Bí mật ký mới. Chỉ được trả về trong phản hồi này |
| `rotated_endpoint_ids` | mảng UUID | Mọi điểm cuối hiện sử dụng bí mật mới |

<Warning>
  Bí mật cũ ngừng được sử dụng ngay lập tức: lần gửi tiếp theo,
  bao gồm cả lần thử lại, được ký bằng bí mật mới. Cho đến khi bộ nhận của bạn có
  bí mật mới, các lần gửi sẽ không vượt qua kiểm tra chữ ký; nếu bộ nhận trả lời
  các lần gửi đó bằng trạng thái không phải 2xx, chúng sẽ được thử lại theo lịch
  24 giờ thông thường, vì vậy hãy cập nhật bộ nhận kịp thời. Nếu bộ nhận của bạn triển khai
  theo từng giai đoạn, hãy để bộ nhận chấp nhận cả hai bí mật trong quá trình triển khai — các
  trình trợ giúp xác minh SDK nhận một danh sách bí mật (xem
  [Xác minh chữ ký webhook](/vi/guides/verify-webhook-signatures)).
</Warning>

---

## Gửi lần gửi thử nghiệm

Gửi một sự kiện `webhook.test` tổng hợp đến một endpoint bằng quy trình phân phối thông thường, bao gồm tuần tự hóa JSON chuẩn tắc, cả hai header chữ ký, ghi nhận phân phối và theo dõi việc thử lại.
Bài kiểm tra nhắm đến endpoint đã chọn bất kể bộ lọc `events` của endpoint đó.

<CodeGroup>
```bash cURL
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-.../test \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```
</CodeGroup>

Endpoint nhận được một phong bì dữ liệu như sau:

```json
{
  "data": {
    "message": "ThunderPhone webhook test",
    "sent_at": "2026-07-17T20:12:34.567890+00:00"
  },
  "event_id": "2ad6507c-7d19-4498-9b2d-7e8f944ab5a1",
  "type": "webhook.test"
}
```

API trả về `200 OK` sau lần thử đầu tiên, ngay cả khi đích trả về lỗi.
Kiểm tra `success`, `status`, `response_code` và `error` để biết
kết quả gửi:

```json
{
  "success": true,
  "event_id": "2ad6507c-7d19-4498-9b2d-7e8f944ab5a1",
  "event_type": "webhook.test",
  "status": "delivered",
  "response_code": 204,
  "error": ""
}
```

`webhook.test` là sự kiện mô phỏng và không thể được thêm vào gói đăng ký `events`
của endpoint. Nếu lần thử đầu tiên thất bại, ThunderPhone sẽ thử lại một lần sau khoảng
một phút rồi dừng; lần gửi sau đó hiển thị `status: "failed"`
trong [Gỡ lỗi lần gửi](#debug-deliveries). Lần gửi thử nghiệm không bao giờ đánh dấu
endpoint là `failing`.

Để cấu hình trình kích hoạt dựa trên cấu trúc sự kiện thực, hãy truyền `event_type`
tùy chọn. Lần gửi vẫn là mô phỏng và chứa `"sample": true`; mẫu liên quan đến cuộc gọi
sử dụng `call_id: 0` và `agent_id: 0`.

```bash
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-.../test \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"event_type":"call.graded"}'
```

`event_type` chấp nhận bất kỳ giá trị nào trong [Loại sự kiện hợp lệ](#valid-event-types).
Việc bỏ qua trường này sẽ giữ nguyên hành vi `webhook.test` chung.

---

## Xóa endpoint

<CodeGroup>
```bash cURL
curl -X DELETE https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-... \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```
</CodeGroup>

Trả về `204 No Content`. Việc gửi đến URL sẽ dừng ngay lập tức;
các lần thử lại đang diễn ra sẽ bị hủy.

---

## Gỡ lỗi lần gửi

Trước khi kết luận rằng webhook chưa được gửi, hãy kiểm tra
[`GET /v1/developer/webhook-deliveries`](/api-reference/webhook-deliveries).
API này hiển thị các lần thử gần đây từ cả hai hệ thống webhook, bao gồm ID cuộc gọi,
nguồn gốc URL, trạng thái HTTP, số lần thử, danh mục lỗi trong danh sách cho phép và thời điểm
thử lại tiếp theo. API này không bao giờ trả về payload sự kiện, bản chép lời, nội dung lỗi đã lưu,
nội dung phản hồi hoặc đường dẫn URL.

Bạn cũng có thể xem cùng lịch sử gần đây trong **Tác nhân → chọn một tác nhân → Webhook →
Lần gửi gần đây**. Các hàng hiển thị nhãn endpoint và nguồn gốc URL được dùng trong lần thử
mới nhất. Đây là trạng thái vận hành thay vì nhật ký kiểm toán bất biến: việc xóa endpoint
cũng xóa các hàng lần gửi của endpoint đó.

Đối với lỗi `404` của n8n, trước tiên hãy xác nhận workflow đang hoạt động, chấp nhận `POST` và sử dụng
URL webhook production thay vì URL thử nghiệm. Lỗi `401` hoặc `403` cho thấy vấn đề về
xác thực hoặc xác minh chữ ký; hết thời gian chờ cho thấy độ trễ
hoặc khả năng sẵn sàng của đích; lỗi TLS cho thấy vấn đề về chuỗi chứng chỉ, tên máy chủ hoặc ngày hết hạn.

---

## Liên quan

<CardGroup cols={2}>
  <Card title="Danh mục sự kiện" icon="list" href="/vi/webhooks/events">
    Danh sách đầy đủ các giá trị `events` mà bạn có thể đăng ký.
  </Card>
  <Card title="Tổng quan về webhook" icon="bolt" href="/vi/webhooks/overview">
    Xác minh chữ ký và ngữ nghĩa gửi.
  </Card>
</CardGroup>
