Realtime
Mọi client chat đều nói chuyện với chat gateway tại https://chat.hatang.dev qua cùng một giao thức WebSocket. Trang này giải thích một phiên chạy từ đầu tới cuối ra sao, để bạn gỡ lỗi widget, hiểu SDK làm gì, hoặc tự viết client. Chi tiết từng khung nằm ở tham chiếu giao thức realtime, các endpoint HTTP ở tham chiếu chat gateway.
Chọn đúng giao diện
| Bạn muốn | Dùng |
|---|---|
| Đặt chat trên website | Widget web; widget tự nói giao thức |
| Đặt chat trong ứng dụng di động | SDK native (Ứng dụng di động) |
| Tự xây giao diện chat cho khách | Giao thức phía khách mô tả bên dưới |
| Đọc và trả lời hội thoại từ server, bot hay CRM | REST API Hỗ trợ với API key, kèm webhook |
Phía nhân viên của gateway phục vụ dashboard và ứng dụng Hạ Tầng trên iPhone, Android và Mac. Nó cần phiên đăng nhập của một nhân viên, không phải API key, nên tích hợp từ server hãy dùng REST API.
Phiên của khách
Một khách truy cập (visitor) là một trình duyệt hoặc một bản cài ứng dụng trên một site. Phiên chạy qua năm bước.
1. Bootstrap
Client gọi POST /widget/v1/sites/{siteId}/bootstrap một lần khi khởi động.
- Trình duyệt được kiểm tra bằng
Origin. Trang phải nằm trên tên miền của site, một tên miền con của nó, hoặc một trong các origin được phép thêm của site. Ngoài ra đều nhận403 origin_not_allowed. - Ứng dụng native gửi khoá ứng dụng trong header
x-hatang-app-keyvàapp.install_id(id cố định cho mỗi bản cài) trong body. Không cần origin.
Body có thể mang token đã lưu (để tiếp tục đúng khách cũ), page hoặc screen, và locale. Response gồm:
| Trường | Là gì |
|---|---|
visitor_token | Thông tin xác thực của khách. Lưu lại (cookie hoặc local storage trên web, keychain trong ứng dụng) và gửi lại lần sau |
visitor | Hồ sơ khách truy cập |
config | Cài đặt widget của site, chiến dịch và nút liên hệ |
availability | Đội đang trực tuyến hay đang trong giờ làm việc |
conversation, timeline | Hội thoại đang mở (nếu có) và 100 phần tử gần nhất khách được thấy |
ws_url | Địa chỉ socket cần mở, ví dụ wss://chat.hatang.dev/ws?site=site_... |
protocol_version | Hiện là 1 |
Các lời gọi HTTP khác trong phiên gửi token trong header x-visitor-token.
2. Kết nối và xác thực
Mở đúng ws_url đã nhận và gửi khung auth trong vòng 5 giây. Mỗi khung là JSON gồm loại t, dữ liệu d, phiên bản v và id tuỳ chọn mà server gửi lại trong câu trả lời.
const ws = new WebSocket(boot.ws_url);
ws.onopen = () => ws.send(JSON.stringify({
t: "auth", v: 1,
d: { token: boot.visitor_token, site_id: "site_...", page: { url: location.href, title: document.title } },
}));
ws.onmessage = (e) => {
const frame = JSON.parse(e.data);
if (frame.t === "ready") render(frame.d.conversation, frame.d.timeline);
if (frame.t === "message") append(frame.d);
};
Server trả lời bằng ready, mang thông tin khách, hội thoại đang mở, dòng thời gian và trạng thái trực của đội. Sau đó cả hai bên gửi ping mỗi 25 giây.
3. Gửi tin
Mỗi tin gửi đi có một client_id do client sinh ra:
{ "t": "message.send", "id": "req_1", "v": 1, "d": { "client_id": "c_9f2", "content": "Shop còn hàng không ạ?" } }
- Hiện tin ở trạng thái đang gửi và chờ tối đa 10 giây để nhận
message.ack, trong đó cóidcủa tin,seqvàconversation_id. Tin đầu tiên của khách sẽ tạo hội thoại. - Hết thời gian chờ hoặc gặp lỗi thì giữ bong bóng ở trạng thái lỗi và gửi lại với cùng
client_id. Server nhận ra và xác nhận tin gốc, nên gửi lại không bao giờ tạo hai tin. - Bản thân tin nhắn cũng quay về dưới dạng khung
message. Loại trùng theoid.
Khách gửi được 5 tin mỗi 10 giây và 60 tin mỗi phút. Tệp được tải lên trước bằng POST /widget/v1/sites/{siteId}/uploads (tối đa 10 MB), rồi gửi theo id trong attachments.
4. Nhận
Khi đang kết nối, khách nhận:
| Khung | Khi nào |
|---|---|
message | Nhân viên, trợ lý AI hoặc hệ thống nhắn vào một hội thoại của khách |
typing | Nhân viên đang gõ |
read | Phía nhân viên đã đọc tới một seq |
availability | Đội chuyển sang trực tuyến hoặc vắng mặt |
conversation.update | Trạng thái, số tin chưa đọc hoặc người đang xử lý của một hội thoại thay đổi |
event | Sự kiện khách nên thấy, như đổi trạng thái hay chuyển sang người thật |
session | Khách vừa được gộp vào một khách khác nhờ identify có chữ ký: lưu token mới |
Client báo lại những gì khách làm bằng typing, read, page (trình duyệt) hoặc screen (ứng dụng), và identify khi khách đăng nhập (Nhận diện khách). Ứng dụng còn gửi app.state khi chuyển xuống nền, để trả lời tới tay khách bằng thông báo đẩy.
5. Kết nối lại mà không mất gì
Mọi tin nhắn và sự kiện trong một hội thoại có seq chỉ tăng. Giữ seq lớn nhất bạn đã thấy. Sau khi kết nối lại, gửi resume {conversation_id, after_seq} và server phát lại từ cơ sở dữ liệu mọi thứ bạn bỏ lỡ. Lịch sử cũ hơn tải qua HTTP với before_seq.
Khi socket đóng, xem mã đóng:
| Mã | Ý nghĩa | Làm gì |
|---|---|---|
| 4001 | Không có auth trong 5 giây | Kết nối lại và gửi auth trước |
| 4003 | Xác thực bị từ chối hoặc bị thu hồi | Dừng; bỏ token và bootstrap một khách mới |
| 4004 | Giao thức của client quá cũ | Trình duyệt tải lại trang; ứng dụng nhắc người dùng cập nhật |
| 4005 | Khung session vừa mang token mới | Kết nối lại ngay với token mới |
| Khác | Mạng hoặc gateway khởi động lại | Kết nối lại với backoff min(30 s, 500 ms · 2^n) cộng jitter |
Phía nhân viên
Dashboard và các ứng dụng Hạ Tầng dùng cùng gateway này dưới tư cách nhân viên:
- Socket. Kết nối của nhân viên xác thực bằng một agent token ngắn hạn. Dashboard lấy token từ phiên đăng nhập và token này chỉ được chấp nhận từ origin của dashboard; ứng dụng di động và Mac nhận token khi nhân viên đăng nhập. Sau đó nhân viên theo dõi hội thoại, nhận các khung
message,conversation.upsert,typingvà trạng thái trực tuyến, và gửi tin, ghi chú, giao việc, đổi trạng thái, gắn tag, đặt nhắc việc. - HTTP. Ứng dụng cũng gọi các endpoint
/agent/*, ví dụGET /agent/conversationsđể lấy danh sách hộp thư,POST /agent/uploadsđể tải tệp (10 MB, video 25 MB; tệp .mov được lưu thành MP4),POST/PATCH/DELETE /agent/cannedcho câu trả lời mẫu riêng của nhân viên, và/agent/conversations/{id}/scheduledcùng/agent/scheduled/{id}cho tin nhắn hẹn giờ (mọi thay đổi tới tất cả nhân viên qua khungscheduled). Mỗi người được 300 lượt đọc và 60 lượt ghi mỗi phút. - Quyền. Token mang vai trò của nhân viên. Người chỉ có quyền xem Hỗ trợ vẫn thấy hộp thư cập nhật trực tiếp nhưng không thao tác được (Nhân viên và phân quyền).
Vì các token này thuộc về một người và hết hạn trong vòng một giờ, chúng không dành cho tích hợp. Để tự động hoá hộp thư, gọi REST API Hỗ trợ bằng API key và đăng ký webhook.
Xử lý sự cố
| Hiện tượng | Nguyên nhân thường gặp |
|---|---|
origin_not_allowed khi bootstrap | Tên miền của trang không phải tên miền của site, tên miền con của nó, hay một origin được phép. Thêm vào ô Origin được phép thêm trên trang của website trong Hỗ trợ → Kênh |
invalid_visitor_token | Token hết hạn, đã reset, hoặc thuộc site khác. Bootstrap lại không kèm token |
product_disabled | Doanh nghiệp đang tắt module Hỗ trợ |
| Socket đóng với mã 4001 | Client gửi khung khác trước auth, hoặc chậm quá 5 giây |
| Tin hiện hai lần | Client không loại trùng bản message quay về theo id |
| Mất tin sau khi rớt mạng | Client không gửi resume với seq cuối cùng |
Bước tiếp theo
- Tham chiếu giao thức realtime: mọi khung, trường và giới hạn
- Tham chiếu chat gateway: endpoint HTTP cho widget, SDK và nhân viên
- JS API: điều khiển widget thay vì tự viết client
- REST API Hỗ trợ