Webhook events AutoCall
Khi cuộc gọi xảy ra -> Zorio POST event tới URL khách hàng đăng ký (HMAC signed).
Events
| Event | Khi nào fire |
|---|---|
autocall.lead.added | Lead push vào campaign thành công |
autocall.lead.audio_ready | Audio TTS render xong, lead sẵn sàng dial |
autocall.call.initiated | Engine bắt đầu originate |
autocall.call.answered | B-leg answer máy |
autocall.dtmf.pressed | User bấm phím (1 event/lần bấm) |
autocall.call.transferred | DTMF action = queue -> chuyển queue thành công |
autocall.call.completed | Cuộc gọi kết thúc (mọi result) |
autocall.lead.completed | Lead hoàn tất tất cả retry (final status) |
autocall.campaign.completed | Campaign hết lead pending |
autocall.tts.render_failed | TTS provider lỗi, lead bị skip |
Envelope chung
Mọi event đều có cấu trúc envelope:
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
event | string | Tên event đầy đủ | autocall.<entity>.<action> |
timestamp | datetime | Lúc Zorio publish event (ISO 8601 UTC) | |
tenant_id | integer | ID tài khoản nhận webhook | |
data | object | Payload event-specific (xem từng event bên dưới) |
data fields theo từng event
autocall.lead.added / autocall.lead.audio_ready / autocall.lead.completed
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
lead_id | integer | ID lead trong AutoCall | |
campaign_id | integer | ID campaign chứa lead | |
phone | string | Số điện thoại lead | E.164 hoặc nội địa VN |
external_ref | string|null | Tham chiếu CRM bên ngoài (nếu khách push kèm) | |
audio_url | string|null | URL audio TTS (chỉ có khi event = audio_ready) | |
final_status | string | Trạng thái cuối (chỉ có khi event = lead.completed) | completed / failed / dnc / max_attempts_reached |
total_attempts | integer | Số lần đã quay số (chỉ có khi lead.completed) | ≥ 1 |
autocall.call.initiated
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
uuid | string | UUID cuộc gọi | |
campaign_id | integer | ID campaign | |
lead_id | integer | ID lead | |
phone | string | Số bị quay | |
attempt_number | integer | Lần quay thứ mấy | ≥ 1 |
caller_id | string | Caller-ID dùng để gọi ra | |
started_at | datetime | Thời điểm originate (ISO 8601 UTC) |
autocall.call.answered
Bao gồm các field như call.initiated cộng thêm:
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
answered_at | datetime | Lúc B-leg nhấc máy (ISO 8601 UTC) |
autocall.dtmf.pressed
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
uuid | string | UUID cuộc gọi | |
campaign_id | integer | ID campaign | |
lead_id | integer | ID lead | |
phone | string | Số đang gọi | |
digit | string | Phím vừa bấm | 0-9, *, # |
pressed_at | datetime | Lúc nhận DTMF (ISO 8601 UTC) |
autocall.call.transferred
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
uuid | string | UUID cuộc gọi | |
campaign_id | integer | ID campaign | |
lead_id | integer | ID lead | |
transfer_target | string | Đích chuyển tiếp | queue:<queue_name> / extension:<ext> |
transferred_at | datetime | Lúc chuyển queue thành công (ISO 8601 UTC) |
autocall.call.completed
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
uuid | string | UUID cuộc gọi | |
campaign_id | integer | ID campaign | |
lead_id | integer | ID lead | |
phone | string | Số đã gọi | |
attempt_number | integer | Lần quay thứ mấy | ≥ 1 |
started_at | datetime | Lúc originate (ISO 8601 UTC) | |
answered_at | datetime|null | Lúc bắt máy (null nếu không nhấc) | |
ended_at | datetime | Lúc cúp máy (ISO 8601 UTC) | |
duration_sec | integer | Tổng thời lượng cuộc gọi (giây) | ≥ 0 |
result | string | Kết quả phân loại | connected / no_answer / busy / failed / voicemail / dnc_blocked |
hangup_cause | string | Mã hangup chuẩn Q.850 từ Zorio PBX | NORMAL_CLEARING / NO_ANSWER / USER_BUSY / CALL_REJECTED / ... |
dtmf_pressed | string|null | Phím cuối user bấm | |
final_action | string|null | Hành động cuối (theo DTMF script) | queue:<name> / hangup / dnc_added / null |
autocall.campaign.completed
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
campaign_id | integer | ID campaign vừa hoàn tất | |
campaign_name | string | Tên campaign | |
total_leads | integer | Tổng số lead trong campaign | ≥ 0 |
total_connected | integer | Số lead bắt máy thành công | ≥ 0 |
completed_at | datetime | Lúc campaign hoàn tất (ISO 8601 UTC) |
autocall.tts.render_failed
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
lead_id | integer | ID lead bị skip | |
campaign_id | integer | ID campaign | |
provider | string | Nhà cung cấp TTS gặp lỗi | tts_provider_01 / tts_provider_02 / tts_provider_03 / local |
error_code | string | Mã lỗi | RATE_LIMIT / INVALID_VOICE / QUOTA_EXCEEDED / UNKNOWN |
error_message | string | Mô tả lỗi | |
failed_at | datetime | Lúc TTS lỗi (ISO 8601 UTC) |
Cấu hình Webhook (qua Admin Console, KHÔNG qua Public API)
Webhook KHÔNG đăng ký qua API
Theo policy bảo mật của Zorio, cấu hình webhook chỉ thực hiện thủ công qua Admin Console (Admin Console). Public API chỉ phục vụ nghiệp vụ AutoCall (campaign / lead / call lifecycle / reports).
Lý do:
- Tránh lạm dụng: nếu cho client tự đăng ký, hacker có thể dùng token để redirect webhook ra URL ngoài tài khoản.
- Đảm bảo audit: mỗi thay đổi webhook config được log ở admin activity.
- Tách bạch nghiệp vụ vs config: public API focused vào dữ liệu cuộc gọi.
Quy trình bạn tích hợp:
- Liên hệ quản trị hệ thống (trong tổ chức) hoặc đội ngũ Zorio support.
- Cung cấp:
- URL endpoint nhận webhook (HTTPS)
- Danh sách events cần subscribe (xem mục Events)
- Tùy chọn: IP allowlist của hạ tầng bạn
- Quản trị hệ thống cấu hình trong Admin Console + chọn events -> lưu.
- Hệ thống generate secret (32 bytes base64) -> gửi cho bạn qua kênh bảo mật.
- Anh chị deploy webhook receiver + dùng secret để verify HMAC signature (xem Headers).
Thay đổi config (đổi URL, thêm events, rotate secret) — cũng qua Admin Console, không qua API.
Delivery payload mẫu (event autocall.call.completed)
{
"event": "autocall.call.completed",
"timestamp": "2026-06-24T08:32:47Z",
"tenant_id": 1,
"data": {
"uuid": "093e1024-...",
"campaign_id": 36,
"lead_id": 78912,
"phone": "84912345678",
"attempt_number": 1,
"started_at": "2026-06-24T08:32:00Z",
"answered_at": "2026-06-24T08:32:05Z",
"ended_at": "2026-06-24T08:32:47Z",
"duration_sec": 42,
"result": "connected",
"hangup_cause": "NORMAL_CLEARING",
"dtmf_pressed": "2",
"final_action": "queue:support_queue"
}
}Headers POST từ Zorio tới URL khách
| Header | Type | Mô tả | Giá trị |
|---|---|---|---|
X-Zorio-Signature | string | HMAC-SHA256 raw body với webhook secret | sha256=<hex> |
X-Zorio-Timestamp | integer | Epoch giây (UTC) — client reject nếu lệch > 300s | |
X-Zorio-Event | string | Convenience copy của event field | autocall.<entity>.<action> |
X-Zorio-Delivery | string | Delivery UUID — dùng dedupe khi retry | UUID v4 |
Content-Type | string | Loại nội dung | application/json; charset=utf-8 |
Verify HMAC
Pseudo-code:
expected = "sha256=" + hex(hmac_sha256(secret, raw_request_body))
if expected != header["X-Zorio-Signature"]: rejectKHÔNG verify trên JSON đã parse — phải dùng raw body bytes.
Retry policy
- 3 lần retry: 5s, 30s, 5 phút
- Sau 3 lần fail -> deadletter (admin xem qua Admin Console)
- HTTP 2xx = success. 4xx/5xx = fail.
Idempotency client-side
Client phải đảm bảo endpoint idempotent (check X-Zorio-Delivery UUID) vì webhook có thể được gửi lại nếu HTTP timeout phía Zorio nhưng response đã thực thi xong phía client.
