Tài liệu tham khảo Chat API: cuộc trò chuyện, tin nhắn, xác nhận đã đọc và sự kiện
Cách gọi Hibira Chat API: yêu cầu có chữ ký, cuộc trò chuyện và thành viên, tin nhắn, bắt kịp tin đã lỡ, xác nhận đã đọc và số chưa đọc, token người dùng cho trình duyệt, tệp đính kèm, push, kiểm duyệt, sự kiện và giới hạn.
Trước khi bắt đầu
Chat API lưu các cuộc trò chuyện cùng tin nhắn và gửi chúng qua kết nối thời gian thực mà ứng dụng của bạn đã có. Máy chủ của bạn quyết định ai ở trong mỗi cuộc trò chuyện và gọi API; client chỉ kết nối, đăng nhập và lắng nghe.
- Đang ở giai đoạn beta. Tài khoản dùng được khi đã tham gia beta hoặc có gói bổ sung Chat. Trước đó mọi lời gọi đều trả về
403 the Chat API is not enabled for this app. Đăng ký danh sách chờ để được tham gia. - URL gốc:
https://ws.hibira.io/apps/APP_ID/chat(dùng host hiển thị trên trang ứng dụng trong portal). - Nội dung là JSON. Lỗi trả về
{"error": "..."}với mã 4xx hoặc 5xx. - ID người dùng do bạn đặt: dùng cùng ID mà client truyền cho
pusher.signin().
Cách hoạt động
- Máy chủ của bạn tạo cuộc trò chuyện và các thành viên (
PUT /conversations/{id}). - Mỗi client kết nối bằng pusher-js và gọi
pusher.signin()với tư cách người dùng của nó. Việc này đăng ký kênh#server-to-user-<user_id>, nên thành viên không cần ủy quyền kênh cho từng cuộc trò chuyện. - Máy chủ của bạn gửi tin nhắn thay người dùng (
POST /conversations/{id}/messages). Hibira lưu nó với số thứ tự tiếp theo của cuộc trò chuyện (seq), rồi gửichat.messagetới mọi thành viên và gọi webhookchat_messagecủa bạn. - Client từng offline đọc những gì đã lỡ bằng
GET /conversations/{id}/messages?after=<seq cuối cùng nó có>.
Mọi thay đổi đều được lưu trước khi gửi sự kiện. Nếu ứng dụng vượt hạn mức tin nhắn hằng ngày, thay đổi vẫn được lưu nhưng không có sự kiện nào được gửi, nên client bắt kịp bằng cách đọc.
Ký yêu cầu
Yêu cầu từ máy chủ của bạn được ký giống hệt các yêu cầu khác của Pusher HTTP API, bằng key và secret của ứng dụng: chuỗi truy vấn mang auth_key, auth_timestamp, auth_version=1.0, body_md5 (khi có nội dung) và auth_signature, là HMAC-SHA256 của METHOD\nPATH\nQUERY với các tham số truy vấn sắp xếp theo tên. Mã ký của bất kỳ thư viện máy chủ Pusher nào cũng dùng được; đây là toàn bộ cách làm trong Node.js:
import crypto from 'node:crypto';
const { PUSHER_APP_ID: id, PUSHER_APP_KEY: key, PUSHER_APP_SECRET: secret } = process.env;
export async function chat(method, path, body) {
const fullPath = `/apps/${id}/chat${path}`;
const json = body === undefined ? '' : JSON.stringify(body);
const params = { auth_key: key, auth_timestamp: Math.floor(Date.now() / 1000), auth_version: '1.0' };
if (json) params.body_md5 = crypto.createHash('md5').update(json).digest('hex');
const query = Object.keys(params).sort().map((k) => `${k}=${params[k]}`).join('&');
const signature = crypto.createHmac('sha256', secret).update(`${method}\n${fullPath}\n${query}`).digest('hex');
const res = await fetch(`https://ws.hibira.io${fullPath}?${query}&auth_signature=${signature}`, {
method, body: json || undefined, headers: { 'Content-Type': 'application/json' },
});
if (!res.ok) throw new Error(`${res.status} ${(await res.json()).error}`);
return res.json();
}
await chat('PUT', '/conversations/order-1042', { name: 'Order #1042', members: ['ann', 'support-bob'] });
await chat('POST', '/conversations/order-1042/messages', { user_id: 'ann', name: 'Ann', text: 'Where is my parcel?' });Tham số truy vấn của GET (như after hay limit) cũng nằm trong chuỗi truy vấn được ký.
Cuộc trò chuyện và thành viên
| Phương thức và đường dẫn | Nội dung hoặc truy vấn | Trả về |
|---|---|---|
PUT /conversations/{id} | name, metadata, members (ID người dùng; bỏ trống để giữ thành viên hiện tại), roles ({user_id: role}), watchers (tối đa 10 kênh private hoặc presence) | 201 khi tạo mới hoặc 200 khi thay thế, {conversation} |
GET /conversations/{id} | {conversation} | |
DELETE /conversations/{id} | {}; xóa luôn thành viên, tin nhắn và tệp | |
POST /conversations/{id}/members | user_ids | {conversation} |
PUT /conversations/{id}/members/{user_id} | role (1–32 ký tự a-z 0-9 _ -; "" là không có) | {conversation} |
DELETE /conversations/{id}/members/{user_id} | {conversation} | |
GET /users/{user_id}/conversations | limit (1–100), before (next của trang trước) | {conversations, next}, hoạt động mới nhất trước, mỗi mục có unread |
Một cuộc trò chuyện:
{"id": "order-1042", "name": "Order #1042", "metadata": {"kind": "support"},
"members": [{"user_id": "ann", "read_seq": 3}, {"user_id": "support-bob", "read_seq": 1, "role": "agent"}],
"last_seq": 3, "created_at": "...", "updated_at": "..."}Vai trò và ghi chú nội bộ. Tin nhắn có visible_to (tối đa 5 vai trò) chỉ đến các thành viên có một trong các vai trò đó: những người khác không nhận, không đọc được và không tính là chưa đọc. Watchers là các kênh private hoặc presence nhận mọi sự kiện của cuộc trò chuyện, để hộp thư của đội theo dõi tất cả cuộc trò chuyện chỉ với một lần đăng ký. Chỉ ủy quyền cho nhân viên của bạn.
Tin nhắn
| Phương thức và đường dẫn | Nội dung hoặc truy vấn | Trả về |
|---|---|---|
POST /conversations/{id}/messages | user_id (một thành viên), name, text, metadata, push, push_title, push_url, visible_to, attachments | 201 {message, push} |
GET /conversations/{id}/messages | after (seq) và limit, hoặc last (n tin mới nhất) | {messages, last_seq}, cũ nhất trước |
GET /conversations/{id}/search | q (1–100 ký tự), before, limit (1–200) | {messages, next}, mới nhất trước |
PUT /conversations/{id}/messages/{seq} | user_id (người gửi), text, metadata | {message} có edited_at |
DELETE /conversations/{id}/messages/{seq} | user_id (người gửi) trong truy vấn; bỏ trống để xóa với tư cách ứng dụng | {message} có deleted_at |
POST /conversations/{id}/messages/{seq}/reactions | user_id, emoji | {message} |
DELETE /conversations/{id}/messages/{seq}/reactions | user_id, emoji trong truy vấn | {message} |
POST /conversations/{id}/system | text, metadata (ví dụ {"event": "transferred", "to": "bob"}) | 201 {message} với kind: "system" |
POST /conversations/{id}/typing | user_id, typing (true hoặc false) | {}; không lưu gì |
Một tin nhắn:
{"id": "...", "seq": 3, "sender": "ann", "name": "Ann", "kind": "text",
"text": "hi", "metadata": {"reply_to": 2}, "reactions": {"👍": ["support-bob"]}, "created_at": "..."}Tin nhắn đã sửa giữ nguyên seq và có thêm edited_at. Tin đã xóa giữ chỗ của nó với deleted_at và không còn nội dung, không thể sửa hay thả cảm xúc nữa (409). Đọc after một số chỉ trả về tin mới hơn, nên client quay lại sẽ đọc lại các tin đang hiển thị (last=n) để cập nhật sửa, xóa và cảm xúc. Tìm kiếm khớp bất kỳ phần nào của từ, bỏ qua hoa thường và ký tự toàn chiều rộng, nên dùng được cho tiếng Trung, Nhật và Hàn. Tin hệ thống cho biết chuyện gì đã xảy ra (tham gia, chuyển giao, đóng): chỉ máy chủ của bạn gửi được, chúng không bao giờ được push hay tính là chưa đọc.
Xác nhận đã đọc và số chưa đọc
| Phương thức và đường dẫn | Nội dung | Trả về |
|---|---|---|
POST /conversations/{id}/read | user_id, seq | {read_seq} |
Vị trí đã đọc của thành viên chỉ tiến lên và không vượt quá last_seq; người gửi một tin coi như đã đọc nó. unread trong danh sách cuộc trò chuyện của người dùng đếm các tin sau read_seq của họ mà không phải tin hệ thống. Mọi thành viên nhận chat.read khi read_seq của ai đó tiến lên.
Trình duyệt và ứng dụng: token người dùng
Client có thể tự gọi Chat API dưới /apps/APP_ID/chat/me, với Authorization: Bearer <user token> và không cần proxy trên máy chủ của bạn. Token là JWT ký bằng secret của ứng dụng (HS256, {sub, exp}, tối đa 30 ngày); máy chủ của bạn tạo nó bằng bất kỳ thư viện JWT nào hoặc bằng POST /tokens:
| Phương thức và đường dẫn | Nội dung | Trả về |
|---|---|---|
POST /tokens | user_id, conversation_id (giới hạn token vào cuộc trò chuyện đó), join (thêm người dùng vào khi dùng lần đầu), ttl (60–86400 giây) | 201 {token, expires_at} |
Có token, client có thể liệt kê cuộc trò chuyện của mình (GET /me/conversations), đọc, tìm kiếm, gửi, sửa và xóa tin của chính mình, thả cảm xúc, đánh dấu đã đọc và báo đang nhập. Người dùng luôn là sub của token. Client không thể tạo cuộc trò chuyện, đổi thành viên, đặt tùy chọn push, tắt tiếng hay cấm: những việc đó ở lại máy chủ của bạn. Mỗi người dùng ghi tối đa 2 lần mỗi giây, dồn tối đa 10 lần. Token có conversation_id và join phù hợp cho khách ẩn danh của chat hỗ trợ: máy chủ của bạn tạo cuộc trò chuyện, kiểm tra khách, rồi cấp token ngắn hạn cho một ID do nó tự tạo.
Tệp đính kèm
- Máy chủ của bạn xin tải lên:
POST /conversations/{id}/attachmentsvớiuser_id,name,content_typevàsize(tối đa 25 MB). Kết quả cóattachmentvàupload(url,method,headers). - Client tải tệp thẳng lên
upload.urltrong vòng 15 phút, với đúng các header đó. - Máy chủ của bạn gửi tin nhắn kèm
attachments:id,namevàcontent_typetừ bước 1 (tối đa 10 mỗi tin; khi đótextcó thể để trống).
Mỗi tệp đính kèm đọc từ API hoặc sự kiện có một url tải xuống được trong một giờ. Tệp tải lên mà không được gửi trong một ngày sẽ bị xóa, và xóa tin nhắn hay cuộc trò chuyện sẽ xóa luôn tệp của nó.
Push cho thành viên offline
Tin nhắn mới được push qua Hibira Push của ứng dụng tới các thành viên không kết nối (push: "offline", mặc định), tới mọi thành viên trừ người gửi ("always"), hoặc không ai cả ("never"). Tiêu đề là tên người gửi và tên cuộc trò chuyện (hoặc push_title), nội dung là 180 ký tự đầu của tin, và push_url mở ra khi chạm vào. Thiết bị đăng ký bằng các SDK push tương thích Beams với cùng ID người dùng. push trong kết quả cho biết đã push bao nhiêu thành viên, hoặc vì sao không push.
Kiểm duyệt
| Phương thức và đường dẫn | Nội dung hoặc truy vấn | Trả về |
|---|---|---|
PUT /moderation/filter | words (tối đa 500), action (mask hoặc reject) | {filter} |
POST /users/{user_id}/ban | reason, until (RFC 3339; bỏ trống là vô thời hạn) | {user_id, banned, until} |
DELETE /users/{user_id}/ban | {user_id, banned} | |
POST /conversations/{id}/members/{user_id}/mute | reason, until | {conversation_id, user_id, muted, until} |
DELETE /conversations/{id}/members/{user_id}/mute | {conversation_id, user_id, muted} | |
POST /conversations/{id}/messages/{seq}/reports | user_id, reason | 201 {report} |
GET /moderation/reports | limit (1–200) | {reports}, mới nhất trước |
Bộ lọc từ kiểm tra mọi tin mới hoặc đã sửa, khớp cả bên trong từ và bỏ qua hoa thường cùng ký tự toàn chiều rộng, nên bắt được cả tiếng Trung và tiếng Nhật. mask thay mỗi chỗ khớp bằng *; reject trả về 422 và không lưu gì. Người dùng bị cấm nhận 403 khi gửi, sửa, thả cảm xúc và báo đang nhập ở mọi cuộc trò chuyện của ứng dụng; thành viên bị tắt tiếng nhận 403 khi gửi và báo đang nhập ở cuộc trò chuyện đó nhưng vẫn đọc được.
Sự kiện và webhook
Sự kiện được gửi tới #server-to-user-<user_id> của từng thành viên liên quan và tới watchers của cuộc trò chuyện. Mỗi sự kiện tính là một tin nhắn vào hạn mức hằng ngày.
| Sự kiện | Gửi tới | Dữ liệu |
|---|---|---|
chat.conversation | mọi thành viên, khi tạo hoặc thay đổi, hoặc khi thêm thành viên | {conversation} |
chat.message | mọi thành viên | {conversation_id, message} |
chat.message_updated | mọi thành viên, sau khi sửa, xóa hoặc thả cảm xúc | {conversation_id, message} |
chat.typing | mọi thành viên trừ người đang nhập | {conversation_id, user_id, typing} |
chat.read | mọi thành viên | {conversation_id, user_id, read_seq} |
chat.left | thành viên bị xóa khỏi cuộc trò chuyện | {conversation_id} |
chat.deleted | mọi thành viên của cuộc trò chuyện bị xóa | {conversation_id} |
const pusher = new Pusher('APP_KEY', { cluster: 'hkg', wsHost: 'ws.hibira.io', userAuthentication: { endpoint: '/pusher/user-auth' } });
pusher.signin();
pusher.user.bind('chat.message', ({ conversation_id, message }) => showMessage(conversation_id, message));Máy chủ của bạn cũng nhận webhook chat_message cho mỗi tin mới: channel là ID cuộc trò chuyện, user_id là người gửi, và data là JSON {"conversation_id", "message"}. Thêm chat_message vào sự kiện của một webhook của ứng dụng để nhận nó.
Giới hạn
| ID cuộc trò chuyện | 1–128 ký tự A-Z a-z 0-9 _ - = @ , . ; |
| ID người dùng | cùng quy tắc với ID người dùng của pusher.signin |
| Thành viên mỗi cuộc trò chuyện | 100 |
| Nội dung tin nhắn | 4.000 ký tự, không được trống |
| Tên cuộc trò chuyện hoặc người gửi | 100 ký tự |
metadata | một đối tượng JSON, tối đa 4.096 byte |
| Tin nhắn mỗi lần đọc | 200 |
| Cảm xúc | mỗi cái 1–32 byte, 20 loại khác nhau mỗi tin |
| Tệp đính kèm | mỗi tệp 25 MB, 10 tệp mỗi tin |
Thao tác ghi dùng chung giới hạn tốc độ HTTP API của ứng dụng (429 khi vượt).
Người dùng hoạt động hằng tháng và thời gian lưu
Một người dùng hoạt động trong tháng (UTC) khi họ gửi tin hoặc đánh dấu đã đọc một cuộc trò chuyện, tính một lần trên mọi ứng dụng của tài khoản. Mỗi tài khoản có sẵn 500 người mỗi tháng; các gói bổ sung Chat nâng lên 1.000, 5.000, 20.000 hoặc 60.000 (các gói). Khi tháng đã đầy, người dùng chưa được tính nhận 429 khi gửi và đánh dấu đã đọc cho đến tháng sau; người đã được tính vẫn dùng bình thường. GET /usage trả về {month, active_users, limit}.
Tin nhắn sửa được hoàn toàn trong 30 ngày. Sau đó, tài khoản có gói trả phí hoặc gói bổ sung Chat giữ chúng trong kho lưu trữ mà API vẫn trả về (chỉ đọc); gói Free không có gói bổ sung thì chúng bị xóa.
Dùng từ một AI agent
Máy chủ MCP của Hibira có các công cụ Chat API, để một AI agent lập trình thiết lập và thử chat giúp bạn: create_conversation, send_message, list_conversations và list_messages. Chúng hoạt động trên chính các ứng dụng của bạn với cùng kiểm tra như một yêu cầu có chữ ký, và cần tài khoản đã có Chat API. Plugin cho agent dành cho Claude Code, Codex, Cursor và các công cụ khác có một skill nối Chat API vào dự án theo các bước này. Nếu cần giao diện trò chuyện dựng sẵn cho React hoặc JavaScript thuần, xem @hibira-io/chat-ui.