Webhook events PBX
Đăng ký webhook
Webhook là cấu hình của khách hàng — đăng ký / xoá / xoay secret qua giao diện Admin (Admin Console). API công khai không expose CRUD subscription.
Tài liệu này document payload schema + HMAC verify để CRM khách hàng tự xử lý event nhận về.
Envelope chung
Mọi event đều có cấu trúc envelope:
| Field | Type | Mô tả |
|---|---|---|
event | string | Tên event (xem chi tiết bên dưới) |
timestamp | datetime | Lúc Zorio publish event (ISO 8601 UTC) |
data | object | Payload event-specific |
pbx.call.ringing
Cuộc gọi tới ext, ext đang đổ chuông chưa nhấc.
data fields
| Field | Type | Mô tả | Giá trị |
|---|---|---|---|
call_uuid | string | UUID cuộc gọi | |
extension | string | Số máy nhánh đang đổ chuông | |
direction | string | Hướng cuộc gọi | inbound / outbound / internal |
caller_number | string | Số gọi đi (caller ID) | |
destination_number | string | Số đích (thường = extension) | |
timestamp | datetime | Lúc bắt đầu đổ chuông | ISO 8601 |
Sample payload
json
{
"event": "pbx.call.ringing",
"timestamp": "2026-06-29T03:30:00Z",
"data": {
"call_uuid": "...",
"extension": "1001",
"direction": "inbound",
"caller_number": "0987654321",
"destination_number": "0900000020",
"timestamp": "2026-06-29T03:30:00Z"
}
}pbx.call.answered
Ext đã nhấc máy.
data fields = giống pbx.call.ringing + thêm:
| Field | Type | Mô tả |
|---|---|---|
answered_at | datetime | Lúc nhấc máy (ISO 8601) |
pbx.call.hangup
Cuộc gọi kết thúc — fire ngay lúc sự kiện kết thúc cuộc gọi từ Zorio PBX.
data fields
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
call_uuid | string | UUID cuộc gọi | |
extension | string | Máy nhánh liên quan | |
direction | string | Hướng cuộc gọi | inbound / outbound / internal |
caller_number | string | Caller ID | |
destination_number | string | Số đích | |
started_at | datetime|null | Lúc cuộc gọi bắt đầu (thời điểm bắt đầu cuộc gọi) | ISO 8601 |
answered_at | datetime|null | Lúc nhấc máy (null nếu không nhấc) | ISO 8601 |
ended_at | datetime | Lúc cúp máy | ISO 8601 |
duration_sec | integer | Tổng thời lượng (giây) | ≥ 0 |
billsec | integer | Thời gian tính tiền (giây) | ≥ 0 |
hangup_cause | string | Mã hangup chuẩn Q.850 từ Zorio PBX | NORMAL_CLEARING / NO_ANSWER / USER_BUSY / CALL_REJECTED / ORIGINATOR_CANCEL / ... |
call_result | string | Kết quả phân loại nhanh | answered (billsec > 0) / no_answer (billsec = 0) |
recording_url | string|null | URL tải ghi âm — null ở event realtime (gửi ngay khi cúp), URL có giá trị ở pbx.cdr.created (sau khi pipeline ghi âm xong) |
Sample payload
json
{
"event": "pbx.call.hangup",
"timestamp": "2026-06-29T03:30:45Z",
"data": {
"call_uuid": "...",
"extension": "1001",
"direction": "inbound",
"caller_number": "0987654321",
"destination_number": "0900000020",
"started_at": "2026-06-29T03:30:00Z",
"answered_at": "2026-06-29T03:30:03Z",
"ended_at": "2026-06-29T03:30:45Z",
"duration_sec": 45,
"billsec": 42,
"hangup_cause": "NORMAL_CLEARING",
"call_result": "answered",
"recording_url": null
}
}pbx.cdr.created
Fire SAU khi pipeline CDR insert row vào DB — có đầy đủ field từ A/B leg processed + recording_url.
data fields
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
call_uuid | string | UUID cuộc gọi (= UUID cuộc gọi) | |
extension | string|null | Máy nhánh (ưu tiên extension_number, fallback agent_extension) | |
direction | string | Hướng | inbound / outbound / internal / local |
caller_number | string | Caller ID | |
destination_number | string | Số đích | |
started_at | datetime|null | Lúc bắt đầu | ISO 8601 |
answered_at | datetime|null | Lúc nhấc | ISO 8601 |
ended_at | datetime|null | Lúc cúp | ISO 8601 |
duration_sec | integer | Tổng thời lượng | ≥ 0 |
billsec | integer | Thời gian tính tiền | ≥ 0 |
hangup_cause | string | Mã hangup | (như pbx.call.hangup) |
result | string | Kết quả phân loại đầy đủ | answered / busy / no_answer / failed / cancelled / rejected / voicemail |
recording_url | string|null | URL nội bộ trỏ tới endpoint download (yêu cầu Bearer Token) | https://app.zorio.vn/api/pbx/cdr/{uuid}/recording hoặc null |
Khác biệt với pbx.call.hangup
pbx.call.hangupfire ngay từ sự kiện thời gian thực —resultchỉ ở mức coarse (answered / no_answer).pbx.cdr.createdfire sau khi pipeline CDR xử lý xong →resultphân loại chi tiết hơn + córecording_url.
Headers POST từ Zorio tới URL khách
| Header | Ý nghĩa |
|---|---|
X-Zorio-Event | pbx.call.hangup |
X-Zorio-Timestamp | epoch giây (UTC). Client reject nếu lệch >300s |
X-Zorio-Delivery | UUID per delivery — dedupe khi retry |
X-Zorio-Signature | sha256=<hex> HMAC-SHA256(secret, raw_body) |
Content-Type | application/json; charset=utf-8 |
Verify HMAC ở client (mẫu Node.js)
js
const crypto = require('crypto');
function verify(req, secret) {
const ts = parseInt(req.headers['x-zorio-timestamp'], 10);
if (Math.abs(Date.now() / 1000 - ts) > 300) return false;
const sig = req.headers['x-zorio-signature'];
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(req.rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}Retry policy
Zorio kỳ vọng client trả 2xx trong 5 giây. Nếu không:
- Lần 2: sau 30 giây
- Lần 3: sau 5 phút
- Lần 4: sau 30 phút
- Max 4 lần → đánh dấu
deadlettertrong bảng nhật ký phân phối webhook
Client nên trả 200 ngay khi nhận event, xử lý async — tránh bị retry chồng.
