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

  1. Máy chủ của bạn tạo cuộc trò chuyện và các thành viên (PUT /conversations/{id}).
  2. 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.
  3. 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ửi chat.message tới mọi thành viên và gọi webhook chat_message của bạn.
  4. 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

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

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

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:

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

  1. Máy chủ của bạn xin tải lên: POST /conversations/{id}/attachments với user_id, name, content_type và size (tối đa 25 MB). Kết quả có attachment và upload (url, method, headers).
  2. Client tải tệp thẳng lên upload.url trong vòng 15 phút, với đúng các header đó.
  3. Máy chủ của bạn gửi tin nhắn kèm attachments: id, name và content_type từ bước 1 (tối đa 10 mỗi tin; khi đó text có 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

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.

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

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.