Webhook
Webhook để GADS đẩy dữ liệu ra endpoint của đối tác khi có sự kiện trong chiến dịch. Automation Hook API để hệ thống bên ngoài gọi vào GADS và đưa dữ liệu vào workflow theo thời gian thực. Trang này mô tả cấu hình trên Back Office (BO), quy tắc schema JSON, cách gửi request và cấu trúc response.
Tổng quan
- Nhận dữ liệu người dùng từ hệ thống bên ngoài và kích hoạt workflow ngay.
- Gửi một object JSON hoặc mảng nhiều object trong một HTTP request.
- Hỗ trợ điều kiện trong workflow theo các trường trong payload.
- Action trong workflow có thể ánh xạ nội dung từ các trường đã gửi.
API Webhook
| Mục | Giá trị |
|---|---|
| Endpoint | /api/automation/hook/{workflowId} |
| Xác thực | Header X-Hook-Secret |
| Payload | Một object JSON hoặc array<object> |
| Trường bắt buộc tối thiểu | phone |
Automation Hook API cho phép hệ thống bên ngoài gửi dữ liệu trực tiếp vào workflow. Mỗi workflow gắn hook có một URL riêng, xác định bởi workflowId trong đường dẫn.
Quy tắc vận hành V1
- Chỉ hỗ trợ
POST. - Trên BO, schema khai báo cho một object.
- Máy chủ nhận body là object đơn hoặc
array<object>(batch). - Máy chủ ánh xạ (resolve) người dùng chủ yếu theo
phonevà có thể tự tạo bản ghi người dùng nếu chưa tồn tại.
https://cdp.b4444.cc/api/automation/hook/{workflowId}
Các khái niệm chính
| Khái niệm | Mô tả |
|---|---|
workflowId | Định danh workflow có kích hoạt hook; mỗi workflow một URL. |
X-Hook-Secret | Chuỗi bí mật xác thực request tới đúng workflow. |
phone | Trường tối thiểu để ánh xạ hoặc tạo người dùng (V1). |
name | Tên hiển thị; dùng làm tên người dùng và trong bước ánh xạ workflow. |
Cấu hình
Trên BO, workflow dùng trigger Webhook được cấu hình trong một panel. BO V1 gọn cho vận hành; phía tích hợp cần URL hook, secret và schema đã được cấu hình sẵn.
Thành phần giao diện
| Thành phần UI | Mô tả | Đối tượng |
|---|---|---|
| Webhook URL | URL cố định theo workflow; client gọi đúng URL này. | Vận hành, đối tác tích hợp |
| Webhook Secret | Chuỗi bí mật do hệ thống tạo khi lưu workflow lần đầu; BO cho phép sao chép. | Vận hành, đối tác tích hợp |
| Schema Fields | Khai báo trường: tên, kiểu dữ liệu, bắt buộc hay không. | Vận hành |
| Xem schema & ví dụ | Xem trước JSON Schema, payload mẫu (một object và batch). | Vận hành, đối tác tích hợp |
Ví dụ cấu hình
Webhook URL:
https://cdp.b4444.cc/api/automation/hook/500
Webhook Secret:
evs_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Schema Fields mẫu
| Tên trường | Kiểu | Bắt buộc | Ghi chú |
|---|---|---|---|
phone | string | Có | Trường hệ thống |
name | string | Tùy workflow (có hoặc không) | Trường nghiệp vụ thường gặp |
voucherCode | string | Không | Trường tùy chỉnh do vận hành thêm |
Schema và Fields
Trên BO V1, schema khai báo cho một đối tượng. Phía máy chủ áp dụng cùng schema cho:
- Yêu cầu đơn lẻ:
{ ... } - Batch:
[{ ... }, { ... }]
Quy tắc schema
- Schema gốc phải có kiểu
object. - Chỉ hỗ trợ trường phẳng (flat); chưa hỗ trợ object lồng nhau (nested) hay mảng object lồng trong trường.
- Kiểu được hỗ trợ:
string,number,boolean. phonelà trường hệ thống bắt buộc, không xóa khỏi schema.- Mỗi trường có thể Required hoặc không.
Tên trường không được sử dụng
Các tên sau được hệ thống dành cho runtime; không dùng làm tên trường nghiệp vụ trong schema:
| Trường hệ thống (nhóm 1) | Trường hệ thống (nhóm 2) |
|---|---|
hook | payload |
value | entrySource |
eventSource | eventType |
hookWorkflowId | hookMethod |
hookReceivedAt | hookIndex |
Ví dụ schema object
{
"type": "object",
"properties": {
"phone": { "type": "string" },
"name": { "type": "string" },
"voucherCode": { "type": "string" },
"totalAmount": { "type": "number" },
"isVip": { "type": "boolean" }
},
"required": ["phone"]
}
Nếu workflow cần lọc hoặc ánh xạ theo một trường, hãy khai báo trường đó trong schema để BO hiển thị trong điều kiện và bước ánh xạ (mapping).
Gửi yêu cầu API
Headers
| Header | Bắt buộc | Mô tả |
|---|---|---|
Content-Type: application/json | Có | Body là JSON. |
X-Hook-Secret | Có | Secret của workflow; sai trả 401 Unauthorized. |
X-Idempotency-Key | Khuyến nghị | Khóa idempotency; nên duy nhất theo từng thao tác nghiệp vụ. |
Gửi 1 object
curl -X POST "https://cdp.b4444.cc/api/automation/hook/500" \
-H "Content-Type: application/json" \
-H "X-Hook-Secret: evs_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Idempotency-Key: order-20260323-0001" \
-d '{
"phone": "0389151977",
"name": "Karis",
"voucherCode": "VC001",
"totalAmount": 250000,
"isVip": true
}'
Gửi batch nhiều object
curl -X POST "https://cdp.b4444.cc/api/automation/hook/500" \
-H "Content-Type: application/json" \
-H "X-Hook-Secret: evs_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Idempotency-Key: batch-20260323-0001" \
-d '[
{
"phone": "0389151977",
"name": "Karis",
"voucherCode": "VC001"
},
{
"phone": "0901234567",
"name": "Lan",
"voucherCode": "VC002"
}
]'
Quy tắc payload
- Body là một
object→ kích hoạt xử lý workflow một lần cho payload đó. - Body là
array<object>→ fan-out: xử lý từng phần tử như một payload riêng. - Mỗi phần tử trong batch phải thỏa schema đã khai báo trên BO.
- Nếu schema bắt buộc
phonethì mọi phần tử trong mảng đều phải cóphone.
Idempotency và khử trùng lặp (dedupe)
Hook có cơ chế chống xử lý trùng — cần thiết khi client có retry tự động.
Khi có header X-Idempotency-Key
- Máy chủ dùng giá trị key làm cơ sở khử trùng.
- Gửi lại cùng body và cùng key → bị coi là trùng (deduped), không xử lý lại như request mới.
- Cùng nội dung nhưng cần chạy lại như lần đầu → phải đổi giá trị key.
Khi không có X-Idempotency-Key
- Hệ thống fall back sang băm (hash) nội dung payload.
- Gửi lại đúng cùng payload có thể vẫn bị khử trùng.
- Môi trường production: luôn gửi
X-Idempotency-Key.
Mỗi thao tác nghiệp vụ dùng một X-Idempotency-Key duy nhất (ví dụ: mã đơn, mã giao dịch, UUID sự kiện nguồn).
Kết quả trả về
Response thành công
Cấu trúc bọc (envelope) chung:
{
"status": 1,
"message": "Gửi thành công",
"data": { ... }
}
Trường trong data
| Trường | Kiểu | Mô tả |
|---|---|---|
workflowId | number | Định danh workflow nhận hook. |
partnerId | string | Đối tác sở hữu workflow. |
triggerType | string | Loại kích hoạt; V1 là hook. |
method | string | Phương thức HTTP đã nhận; V1 là POST. |
url | string | URL mà máy chủ ghi nhận cho request. |
receivedCount | number | Số object trong payload; với batch bằng số phần tử mảng. |
enqueued | number | Số phần tử đưa vào hàng đợi (enqueue) thành công. |
deduped | number | Số phần tử trùng, không đưa vào hàng đợi lại. |
skipped | number | Số phần tử bỏ qua (ví dụ không khớp audience). |
rejected | number | Số phần tử từ chối khi phân phối xử lý. |
hookConfig | object | Siêu dữ liệu cấu hình hook tại thời điểm xử lý (hỗ trợ kiểm tra). |
items | array | Kết quả chi tiết theo từng phần tử. |
Trường trong data.hookConfig
| Trường | Mô tả |
|---|---|
enabled | Hook đang bật và nhận request hay không. |
secretConfigured | Workflow đã được gán secret hay chưa. |
phoneField | Tên trường ánh xạ người dùng theo số điện thoại. |
userIdField | Trường tương thích; V1 ưu tiên phone. |
idByOaField | Trường tương thích; V1 ưu tiên phone. |
fullNameField | Trường họ tên, thường là name. |
autoCreateUser | Tự tạo người dùng nếu chưa ánh xạ được. |
dedupeHeader | Tên header idempotency, mặc định X-Idempotency-Key. |
dedupeField | Trường trong payload dùng khử trùng nếu cấu hình; V1 mặc định không dùng. |
payloadQueryParam | Tên tham số query khi gửi payload qua URL; V1 là payload. |
methods | Danh sách phương thức HTTP cho phép; V1 là ["POST"]. |
schema | JSON Schema object áp dụng tại thời điểm request. |
Trường trong data.items[]
| Trường | Mô tả |
|---|---|
index | Chỉ số phần tử (bắt đầu từ 0); payload một object thường chỉ có 0. |
outcome | Một trong: enqueued, deduped, skipped, rejected. |
message | Mô tả ngắn kết quả xử lý. |
userId | Định danh người dùng đã ánh xạ cho phần tử. |
statusId | ID trạng thái trên hàng đợi khi outcome là enqueued. |
Ví dụ response — enqueued
{
"status": 1,
"message": "Gửi thành công",
"data": {
"workflowId": 500,
"partnerId": "kimnguyenbao",
"triggerType": "hook",
"method": "POST",
"url": "https://cdp.b4444.cc/api/automation/hook/500",
"receivedCount": 1,
"enqueued": 1,
"deduped": 0,
"skipped": 0,
"rejected": 0,
"hookConfig": {
"enabled": true,
"secretConfigured": true,
"phoneField": "phone",
"fullNameField": "name",
"autoCreateUser": true,
"dedupeHeader": "X-Idempotency-Key",
"methods": ["POST"],
"schema": {
"type": "object",
"properties": {
"phone": { "type": "string" },
"name": { "type": "string" }
},
"required": ["phone"]
}
},
"items": [
{
"index": 0,
"outcome": "enqueued",
"message": "queued",
"userId": "188986237",
"statusId": 6734
}
]
}
}
Ví dụ response — deduped
{
"status": 1,
"message": "Gửi thành công",
"data": {
"workflowId": 500,
"receivedCount": 1,
"enqueued": 0,
"deduped": 1,
"skipped": 0,
"rejected": 0,
"items": [
{
"index": 0,
"outcome": "deduped",
"message": "duplicate skipped",
"userId": "188986237"
}
]
}
}
Response lỗi (HTTP 4xx / 5xx)
{
"status": 0,
"message": "..."
}
Bảng mã HTTP và ngữ cảnh
| HTTP status | Ngữ cảnh | Ví dụ message |
|---|---|---|
400 | Workflow không hợp lệ, triggerConfig sai, JSON không hợp lệ, payload không khớp schema | Payload không hợp lệ tại $.phone: thiếu field bắt buộc |
401 | X-Hook-Secret sai hoặc thiếu | Sai secret của workflow hook. |
403 | Hook tạm tắt | Workflow hook đang bị tắt. |
404 | Không tồn tại workflowId | Không tìm thấy workflow. |
405 | Phương thức khác POST (hoặc không nằm trong methods) | HTTP method không được phép cho workflow hook này. |
409 | Workflow chưa published hoặc chưa có bước bắt đầu hợp lệ | Workflow chưa ở trạng thái published. |
500 | Lỗi máy chủ nội bộ | Lỗi: ... |
Ví dụ lỗi sai secret
{
"status": 0,
"message": "Sai secret của workflow hook."
}
Ví dụ lỗi schema
{
"status": 0,
"message": "Payload không hợp lệ tại $.phone: thiếu field bắt buộc"
}