ODS
API ReferenceWebhook

Tích hợp Webhook và Popup cuộc gọi

Đặc tả payload Webhook cuộc gọi ODS, từ điển tham số, chuỗi JSON mẫu và ý nghĩa ứng dụng Popup.

Tài liệu này mô tả cấu trúc dữ liệu JSON Webhook do tổng đài ODS gửi đến endpoint khách hàng cung cấp, từ điển tham số, chuỗi sự kiện mẫu và ý nghĩa của dữ liệu đối với Popup. Cách triển khai ứng dụng tiếp nhận nằm ngoài contract dịch vụ ODS.


Hợp đồng HTTP tiếp nhận

Hệ thống tổng đài ODS đóng vai trò là bên gửi (Sender), chủ động phát request HTTP POST đến địa chỉ endpoint do doanh nghiệp thiết lập (Receiver):

  • Địa chỉ tiếp nhận: Endpoint URL công khai thuộc máy chủ của doanh nghiệp (ví dụ: https://crm.example.com/api/webhook/ods-call).
  • Giao thức và Phương thức: HTTP POST, Content-Type: application/json.
  • Trường định danh sự kiện: Trường Event (chữ cái đầu viết hoa, mang một trong 5 giá trị: register, show, answer, hide, finish). Tuyệt đối không dùng trường Status.
  • Xác thực tùy chọn: Khách hàng có thể cung cấp một khóa đã thống nhất với ODS. Khóa được gửi trong field apikey của body JSON; không dùng ApiKey, X-API-Key, Authorization và không nhầm với REST AuthKey.
  • Phản hồi xác nhận tiếp nhận:
    • Endpoint trả HTTP status thuộc dải 2xx sau khi tiếp nhận body JSON.
    • HTTP 2xx chỉ xác nhận endpoint đã tiếp nhận request, không phản ánh trạng thái cuộc gọi và không phải ACK trước khi dữ liệu được tiếp nhận.
    • Contract hiện tại không áp đặt response JSON bắt buộc.

Bảng từ điển tham số Payload

Để thuận tiện tra cứu theo đúng nghiệp vụ phát triển, toàn bộ 25 tham số trong gói tin Webhook ODS được phân chia thành 4 nhóm chức năng bên dưới.

Nhận diện cuộc gọi và máy nhánh

Nhóm tham số cốt lõi phục vụ điều phối và đồng bộ cửa sổ cuộc gọi (Popup CRM):

Tên trườngKiểu dữ liệuÝ nghĩa nghiệp vụSự kiện xuất hiệnLưu ý kỹ thuật
EventstringTên sự kiện vòng đờiMọi sự kiệnGiá trị: register, show, answer, hide, finish. Không dùng trường Status.
LIDstringMã phiên tổng thể (Linked ID)Mọi sự kiệnKhóa liên kết xuyên suốt toàn bộ cuộc gọi. Mọi sự kiện cùng một cuộc gọi đều chung LID.
UidstringMã định danh nhánh kênh thoại (Unique ID)show, answer, hide, finishCó vai trò khác LID. Giá trị có thể bằng LID trong một số kịch bản, nhưng không được giả định luôn bằng nhau.
DirstringHướng cuộc gọiMọi sự kiệnNhận giá trị: Inbound (gọi vào), Outbound (gọi ra), hoặc Local (gọi nội bộ).
CIDstringSố điện thoại khách hàngMọi sự kiệnLuôn đại diện cho số khách hàng ở cả 2 chiều gọi (gọi vào là số người gọi, gọi ra là số người nhận).
DIDstringĐầu số Hotline doanh nghiệpHầu hết sự kiệnĐầu số tổng đài đại diện của doanh nghiệp.
ExtstringSố máy nhánh nội bộshow, answer, hide, finishSố máy lẻ nhân viên tiếp nhận/thực hiện cuộc gọi (ví dụ: 101, 102).
srcNamestringTên hiển thị người gọi/nhân viênTùy kịch bảnTên nhân viên (gọi ra) hoặc tên nhận diện theo danh bạ tổng đài (gọi vào).

Mốc thời gian và tính cước

Nhóm tham số phục vụ đo lường thời lượng đàm thoại, kiểm tra SLA và đối soát cước viễn thông:

Tên trườngKiểu dữ liệuÝ nghĩa nghiệp vụSự kiện xuất hiệnLưu ý kỹ thuật
TimeCallstringThời điểm khởi tạo cuộc gọiMọi sự kiệnĐịnh dạng YYYY-MM-DD HH:mm:ss theo giờ máy chủ tổng đài.
TimeDialstring | falseThời điểm máy nhánh bắt đầu đổ chuôngshow, hide, finishĐịnh dạng YYYY-MM-DD HH:mm:ss. Có thể mang giá trị false nếu nhánh chưa kịp kích hoạt chuông.
TimeAnswerstringThời điểm bắt đầu đàm thoạianswer, finishChỉ xuất hiện khi có người nhấc máy. Dùng làm mốc bắt đầu tính thời gian đàm thoại.
TimeStopDialstringThời điểm máy nhánh dừng đổ chuônghideĐịnh dạng YYYY-MM-DD HH:mm:ss. Ghi nhận chính xác lúc máy nhánh tắt chuông.
TimeEndstringThời điểm kết thúc cuộc gọifinishĐịnh dạng YYYY-MM-DD HH:mm:ss. Đánh dấu thời điểm hai bên ngắt kết nối hoàn toàn.
TimeBillSecstringThời điểm bắt đầu tính cước viễn thôngInbound qua IVR/QueueChú ý: Là mốc thời gian timestamp (YYYY-MM-DD HH:mm:ss), không phải số giây thời lượng.
BillSecBystringNguyên nhân bắt đầu tính cướcInbound qua IVR/QueueKịch bản kích hoạt tính cước viễn thông (ví dụ: IVR khi nghe lời chào, hoặc Queue).

Kịch bản tổng đài và kênh viễn thông

Nhóm tham số kỹ thuật phục vụ phân tích luồng điều hướng VoIP và hàng đợi:

Tên trườngKiểu dữ liệuÝ nghĩa nghiệp vụSự kiện xuất hiệnLưu ý kỹ thuật
IVRstringTên kịch bản tương tác phímInbound qua IVRTên kịch bản lời chào tương tác (ví dụ: ivr-14).
QueuestringSố định danh hàng đợiInbound qua QueueSố nhóm tiếp nhận cuộc gọi tập trung (ví dụ: 7800).
ChstringKênh nguồn Asterisk (Source Channel)Hầu hết sự kiệnĐịnh danh kênh viễn thông gốc (ví dụ: PJSIP/MOBI... hoặc PJSIP/7877...).
ChDeststringKênh đích Asterisk (Destination Channel)answer, finish, OutboundĐịnh danh kênh viễn thông kết nối đến đầu cuối đối phương.
Call-IDstringKhóa SIP Call-IDTùy sự kiệnĐịnh danh bản tin SIP cấp thấp. Có thể là chuỗi rỗng "".
DialExistbooleanĐánh dấu nhánh từng được quay sốInbound theo nhómMang giá trị true khi tổng đài đã từng phát lệnh đổ chuông đến máy nhánh này.

Kết quả xử lý, file ghi âm và bảo mật

Nhóm tham số phục vụ lưu trữ nhật ký CDR, tải file ghi âm và xác thực nguồn gửi:

Tên trườngKiểu dữ liệuÝ nghĩa nghiệp vụSự kiện xuất hiệnLưu ý kỹ thuật
DispositionstringKết quả cuộc gọi / trạng thái nhánhhide, finishNhận các giá trị: ANSWERED, ANSWERED_ELSEWHERE, BUSY, NO ANSWER, FAILED.
recordingfilestringTên file ghi âm gốcanswer, finish, OutboundTên file âm thanh trên máy chủ (ví dụ: in-089616...wav). Chưa đồng nghĩa file đã sẵn sàng tải.
recordingfileURLstringURL tải/nghe file ghi âmfinish (khi có nghe máy)Đường dẫn HTTPS chính thức có mã bảo mật để tải hoặc nghe lại tệp ghi âm từ ODS.
apikeystring | nullKhóa xác thực Webhook tùy chọnMọi sự kiện trong bodyODS gửi đúng field chữ thường apikey. Payload mẫu chưa cấu hình khóa có giá trị null; khi đã thống nhất khóa, ứng dụng tiếp nhận kiểm tra đúng giá trị đó.

Dữ liệu JSON mẫu thực tế

Dưới đây là các chuỗi sự kiện JSON hoàn chỉnh dựa trên dữ liệu log thực tế từ hệ thống ODS (thông tin số thuê bao và định danh đã được ẩn danh):

1. Sự kiện register (Khách hàng kết nối vào tổng đài)

{
  "Event": "register",
  "LID": "1710000001.1001",
  "Dir": "Inbound",
  "CID": "0901234567",
  "DID": "02873007788",
  "TimeCall": "2026-10-15 14:57:30",
  "Ch": "PJSIP/MOBI02873007788-00003968",
  "apikey": null
}

2. Sự kiện show (Đổ chuông máy nhánh 101 trong nhóm)

{
  "Event": "show",
  "LID": "1710000001.1001",
  "Dir": "Inbound",
  "CID": "0901234567",
  "DID": "02873007788",
  "TimeCall": "2026-10-15 14:57:30",
  "TimeBillSec": "2026-10-15 14:57:31",
  "BillSecBy": "IVR",
  "IVR": "ivr-14",
  "Queue": "7800",
  "DialExist": true,
  "TimeDial": "2026-10-15 14:57:39",
  "Ext": "101",
  "Uid": "1710000001.1002",
  "srcName": "Nguyen Van A",
  "Ch": "PJSIP/MOBI02873007788-00003968",
  "apikey": null
}

3. Sự kiện show (Đổ chuông máy nhánh 102 trong nhóm)

{
  "Event": "show",
  "LID": "1710000001.1001",
  "Dir": "Inbound",
  "CID": "0901234567",
  "DID": "02873007788",
  "TimeCall": "2026-10-15 14:57:30",
  "TimeBillSec": "2026-10-15 14:57:31",
  "BillSecBy": "IVR",
  "IVR": "ivr-14",
  "Queue": "7800",
  "DialExist": true,
  "TimeDial": "2026-10-15 14:57:39",
  "Ext": "102",
  "Uid": "1710000001.1003",
  "srcName": "Nguyen Van A",
  "Ch": "PJSIP/MOBI02873007788-00003968",
  "apikey": null
}

4. Sự kiện answer (Máy nhánh 101 nhấc máy tiếp nhận)

{
  "Event": "answer",
  "LID": "1710000001.1001",
  "Dir": "Inbound",
  "CID": "0901234567",
  "DID": "02873007788",
  "TimeCall": "2026-10-15 14:57:30",
  "TimeBillSec": "2026-10-15 14:57:31",
  "BillSecBy": "IVR",
  "IVR": "ivr-14",
  "Queue": "7800",
  "DialExist": true,
  "TimeAnswer": "2026-10-15 14:57:45",
  "Ch": "PJSIP/MOBI02873007788-00003968",
  "ChDest": "PJSIP/101-0000396a",
  "Ext": "101",
  "Uid": "1710000001.1002",
  "recordingfile": "in-02873007788-0901234567-20261015-145730-1710000001.1001.wav",
  "apikey": null
}

5. Sự kiện hide (Máy nhánh 102 dừng chuông do máy khác đã nghe)

{
  "Event": "hide",
  "LID": "1710000001.1001",
  "Dir": "Inbound",
  "CID": "0901234567",
  "DID": "02873007788",
  "TimeCall": "2026-10-15 14:57:30",
  "TimeBillSec": "2026-10-15 14:57:31",
  "BillSecBy": "IVR",
  "IVR": "ivr-14",
  "Queue": "7800",
  "DialExist": true,
  "Ext": "102",
  "TimeDial": "2026-10-15 14:57:39",
  "TimeStopDial": "2026-10-15 14:57:45",
  "Uid": "1710000001.1003",
  "srcName": "Nguyen Van A",
  "Disposition": "ANSWERED_ELSEWHERE",
  "Ch": "PJSIP/MOBI02873007788-00003968",
  "apikey": null
}

6. Sự kiện finish (Cuộc gọi kết thúc, tổng kết cước và file ghi âm)

{
  "Event": "finish",
  "LID": "1710000001.1001",
  "Dir": "Inbound",
  "CID": "0901234567",
  "DID": "02873007788",
  "TimeCall": "2026-10-15 14:57:30",
  "TimeBillSec": "2026-10-15 14:57:31",
  "BillSecBy": "IVR",
  "IVR": "ivr-14",
  "Queue": "7800",
  "DialExist": true,
  "Ext": "101",
  "TimeDial": "2026-10-15 14:57:39",
  "TimeAnswer": "2026-10-15 14:57:45",
  "TimeEnd": "2026-10-15 14:57:51",
  "Uid": "1710000001.1002",
  "srcName": "Nguyen Van A",
  "Disposition": "ANSWERED",
  "Ch": "PJSIP/MOBI02873007788-00003968",
  "recordingfile": "in-02873007788-0901234567-20261015-145730-1710000001.1001.wav",
  "recordingfileURL": "https://recording.example.com/Home?ID=encrypt_hash_token_string",
  "apikey": null
}

Ý nghĩa dữ liệu đối với Popup

Popup là một ứng dụng của payload Webhook. ODS cung cấp sự kiện và dữ liệu cuộc gọi; cách khách hàng tổ chức backend, giao diện hoặc lưu trữ không thuộc contract này.

  1. Khi nhận sự kiện show:
    • CID cho biết số khách hàng và Ext cho biết máy nhánh liên quan; ứng dụng khách hàng có thể dùng hai giá trị này để chọn thông tin Popup phù hợp.
  2. Khi nhận sự kiện answer:
    • Dữ liệu cho biết nhánh cuộc gọi đã được trả lời.
  3. Khi nhận sự kiện hide:
    • hide mô tả một nhánh ngừng đổ chuông. Trong cuộc gọi nhóm, hide của nhánh có ANSWERED_ELSEWHERE không đồng nghĩa toàn bộ cuộc gọi theo LID đã finish.
  4. Khi nhận sự kiện finish:
    • Dữ liệu cho biết cuộc gọi kết thúc và có thể kèm thông tin tổng kết như Disposition hoặc recordingfileURL.

Giới hạn định danh thông báo

  • Correlation cấp cuộc gọi: LID liên kết các sự kiện thuộc cùng một cuộc gọi. Một LID có thể xuất hiện trong nhiều thông báo khác nhau.
  • Nhánh gọi: Uid nhận diện nhánh kênh thoại và Ext nhận diện máy nhánh liên quan. Một cuộc gọi có thể có nhiều Uid/Ext; các field này không phải định danh duy nhất của thông báo.
  • Định danh duy nhất của thông báo: Payload hiện tại chưa có event ID duy nhất đã được xác nhận. Vì vậy không thể dùng LID, LID + Ext hoặc một công thức ghép field để khẳng định phổ quát rằng hai request là trùng nhau.
  • Ứng dụng tiếp nhận: Nếu cần chống xử lý trùng, khách hàng phải xác định và kiểm thử quy tắc theo kịch bản tích hợp thực tế. Tài liệu hiện tại không xác nhận retry, timeout, exactly-once hay thứ tự nhận tuyệt đối.
  • Nhiều tổng đài: Khi một endpoint nhận dữ liệu từ nhiều nguồn tích hợp, cần phân vùng correlation theo nguồn tích hợp + LID. Contract không tự thêm field nguồn mới và apikey: null không xác định được tổng đài gửi.

Ý nghĩa các giá trị kết quả cuộc gọi (Disposition)

Trường Disposition phản ánh kết quả xử lý của một nhánh hoặc của toàn bộ cuộc gọi:

Giá trịÝ nghĩa thực tếNgữ cảnh xuất hiện
ANSWEREDCuộc gọi đã được tiếp nhận và đàm thoại thành công.Xuất hiện trong sự kiện finish khi có ít nhất một bên bắt máy.
ANSWERED_ELSEWHERECuộc gọi đã được một máy nhánh khác trong nhóm nhấc máy trả lời.Xuất hiện trong sự kiện hide của các máy nhánh không kịp nhấc máy. Không phải cuộc gọi nhỡ của khách hàng.
BUSYMáy bận (người nhận từ chối cuộc gọi hoặc đang có cuộc gọi khác).Xuất hiện trong hide hoặc finish.
NO ANSWERHết thời gian đổ chuông nhưng không có người nhấc máy.Xuất hiện trong hide hoặc finish của cuộc gọi nhỡ.
FAILEDCuộc gọi thất bại do lỗi kỹ thuật mạng hoặc thuê bao không liên lạc được.Xuất hiện trong finish.

[!NOTE] Phân định thời gian đàm thoại và cước viễn thông:

  • Thời lượng đàm thoại thực tế của nhân viên tính bằng: TimeEnd - TimeAnswer (tính theo giây).
  • Không lấy TimeEnd - TimeCall làm thời gian đàm thoại vì khoảng cách này bao gồm cả thời gian nghe lời chào IVR và thời gian chờ đổ chuông.

Xử lý sự cố thường gặp (Troubleshooting)

Hiện tượng lỗiNguyên nhân gốc rễHướng xử lý
Endpoint không nhận được request nào1. URL cấu hình sai hoặc server bị chặn firewall.
2. Chưa gửi thông tin cho ODS cấu hình kích hoạt.
- Kiểm tra server có nhận được request từ Internet qua công cụ kiểm thử (như Webhook.site).
- Liên hệ bộ phận kỹ thuật ODS xác nhận trạng thái kích hoạt Webhook.
Lỗi HTTP 401 UnauthorizedTích hợp đã dùng xác thực tùy chọn nhưng giá trị apikey trong body không khớp giá trị hai bên đã thống nhất.Đối chiếu cấu hình với ODS và giá trị ứng dụng tiếp nhận đang kiểm tra. Không coi null là cách bỏ qua một khóa sai.
Một cuộc gọi phát nhiều sự kiện showCuộc gọi đến nhóm máy nhánh (Queue / Ring Group) làm nhiều máy đổ chuông cùng lúc.Đây là hành vi bình thường. Ứng dụng tiếp nhận dùng Ext để phân biệt máy nhánh liên quan đến từng thông báo.
Không có trường Ext trong sự kiện registerCuộc gọi vào mới tiếp nhận ở tầng đầu số/IVR, chưa định tuyến đến máy lẻ nào.Không giả định mọi sự kiện đều có Ext; đối chiếu theo loại Event.
Không có trường recordingfileURLCuộc gọi nhỡ (không có người bắt máy) hoặc cuộc gọi chưa kết thúc.Link ghi âm chỉ được máy chủ ODS sinh ra duy nhất tại sự kiện finish đối với các cuộc gọi có trạng thái ANSWERED.
Popup hiển thị sai máy nhánhỨng dụng khách hàng ánh xạ sai Ext hoặc bỏ qua ngữ cảnh nhánh gọi.Đối chiếu Ext, Uid, LID và Event của thông báo với kịch bản thực tế.

Bài viết liên quan