เอกสารอ้างอิง Chat API: บทสนทนา ข้อความ สถานะอ่านแล้ว และอีเวนต์
วิธีเรียก Hibira Chat API: คำขอที่ลงลายเซ็น บทสนทนาและสมาชิก ข้อความ การตามข้อความที่พลาด สถานะอ่านแล้วและจำนวนที่ยังไม่อ่าน โทเคนผู้ใช้สำหรับเบราว์เซอร์ ไฟล์แนบ พุช การกลั่นกรอง อีเวนต์ และขีดจำกัด
ก่อนเริ่มต้น
Chat API เก็บบทสนทนาและข้อความ แล้วส่งผ่านการเชื่อมต่อเรียลไทม์ที่แอปของคุณมีอยู่แล้ว เซิร์ฟเวอร์ของคุณเป็นผู้กำหนดว่าใครอยู่ในบทสนทนาใดและเป็นผู้เรียก API ส่วนไคลเอนต์แค่เชื่อมต่อ ลงชื่อเข้าใช้ และรับฟัง
- อยู่ในช่วงเบต้า บัญชีใช้งานได้เมื่ออยู่ในเบต้าหรือมีแพ็กเสริม Chat ก่อนหน้านั้นทุกการเรียกจะได้
403 the Chat API is not enabled for this appลงชื่อในรายชื่อรอ เพื่อขอใช้งาน - Base URL:
https://ws.hibira.io/apps/APP_ID/chat(ใช้โฮสต์ที่แสดงในหน้าแอปบนพอร์ทัล) - เนื้อหาเป็น JSON ข้อผิดพลาดตอบเป็น
{"error": "..."}พร้อมสถานะ 4xx หรือ 5xx - ID ผู้ใช้เป็นของคุณเอง: ใช้ ID เดียวกับที่ไคลเอนต์ส่งให้
pusher.signin()
วิธีการทำงาน
- เซิร์ฟเวอร์ของคุณสร้างบทสนทนาและสมาชิก (
PUT /conversations/{id}) - แต่ละไคลเอนต์เชื่อมต่อด้วย pusher-js แล้วเรียก
pusher.signin()ในนามผู้ใช้ของตน ซึ่งจะสมัครรับ#server-to-user-<user_id>สมาชิกจึงไม่ต้องขออนุญาตช่องสำหรับแต่ละบทสนทนา - เซิร์ฟเวอร์ของคุณส่งข้อความแทนผู้ใช้ (
POST /conversations/{id}/messages) Hibira จะเก็บด้วยหมายเลขลำดับถัดไปของบทสนทนา (seq) แล้วส่งchat.messageให้สมาชิกทุกคนและเรียกเว็บฮุกchat_messageของคุณ - ไคลเอนต์ที่เคยออฟไลน์อ่านข้อความที่พลาดด้วย
GET /conversations/{id}/messages?after=<seq ล่าสุดที่มี>
ทุกการเปลี่ยนแปลงจะถูกเก็บก่อนส่งอีเวนต์ใด ๆ หากแอปเกินโควตาข้อความรายวัน การเปลี่ยนแปลงยังถูกเก็บแต่จะไม่มีอีเวนต์ส่งออกไป ไคลเอนต์จึงตามให้ทันได้ด้วยการอ่าน
การลงลายเซ็นคำขอ
คำขอจากเซิร์ฟเวอร์ของคุณลงลายเซ็นแบบเดียวกับคำขออื่นของ Pusher HTTP API ด้วยคีย์และซีเคร็ตของแอป: query string มี auth_key, auth_timestamp, auth_version=1.0, body_md5 (เมื่อมีเนื้อหา) และ auth_signature ซึ่งคือ HMAC-SHA256 ของ METHOD\nPATH\nQUERY โดยเรียงพารามิเตอร์ตามชื่อ โค้ดลงลายเซ็นของไลบรารีเซิร์ฟเวอร์ Pusher ใดก็ใช้ได้ นี่คือทั้งหมดใน 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?' });พารามิเตอร์ของ GET (เช่น after หรือ limit) ก็เป็นส่วนหนึ่งของ query ที่ลงลายเซ็นด้วย
บทสนทนาและสมาชิก
| เมธอดและพาธ | เนื้อหาหรือ query | ผลลัพธ์ |
|---|---|---|
PUT /conversations/{id} | name, metadata, members (ID ผู้ใช้; เว้นไว้เพื่อคงสมาชิกเดิม), roles ({user_id: role}), watchers (ช่อง private หรือ presence สูงสุด 10 ช่อง) | 201 เมื่อสร้างใหม่ หรือ 200 เมื่อแทนที่, {conversation} |
GET /conversations/{id} | {conversation} | |
DELETE /conversations/{id} | {}; ลบสมาชิก ข้อความ และไฟล์ด้วย | |
POST /conversations/{id}/members | user_ids | {conversation} |
PUT /conversations/{id}/members/{user_id} | role (1–32 ตัวของ a-z 0-9 _ -; "" คือไม่มี) | {conversation} |
DELETE /conversations/{id}/members/{user_id} | {conversation} | |
GET /users/{user_id}/conversations | limit (1–100), before (next ของหน้าก่อน) | {conversations, next} เรียงตามกิจกรรมล่าสุด แต่ละรายการมี unread |
บทสนทนา:
{"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": "..."}บทบาทและโน้ตภายใน ข้อความที่มี visible_to (สูงสุด 5 บทบาท) จะถึงเฉพาะสมาชิกที่มีบทบาทนั้น คนอื่นจะไม่ได้รับ อ่านไม่ได้ และไม่นับเป็นยังไม่อ่าน Watchers คือช่อง private หรือ presence ที่ได้รับทุกอีเวนต์ของบทสนทนา ให้กล่องข้อความของทีมติดตามทุกบทสนทนาได้ด้วยการสมัครเดียว อนุญาตเฉพาะพนักงานของคุณเท่านั้น
ข้อความ
| เมธอดและพาธ | เนื้อหาหรือ query | ผลลัพธ์ |
|---|---|---|
POST /conversations/{id}/messages | user_id (สมาชิก), name, text, metadata, push, push_title, push_url, visible_to, attachments | 201 {message, push} |
GET /conversations/{id}/messages | after (seq) และ limit หรือ last (n ข้อความล่าสุด) | {messages, last_seq} เก่าสุดก่อน |
GET /conversations/{id}/search | q (1–100 ตัวอักษร), before, limit (1–200) | {messages, next} ใหม่สุดก่อน |
PUT /conversations/{id}/messages/{seq} | user_id (ผู้ส่ง), text, metadata | {message} พร้อม edited_at |
DELETE /conversations/{id}/messages/{seq} | user_id (ผู้ส่ง) ใน query; เว้นไว้เพื่อลบในนามแอป | {message} พร้อม deleted_at |
POST /conversations/{id}/messages/{seq}/reactions | user_id, emoji | {message} |
DELETE /conversations/{id}/messages/{seq}/reactions | user_id, emoji ใน query | {message} |
POST /conversations/{id}/system | text, metadata (เช่น {"event": "transferred", "to": "bob"}) | 201 {message} ที่มี kind: "system" |
POST /conversations/{id}/typing | user_id, typing (true หรือ false) | {}; ไม่มีการเก็บ |
ข้อความ:
{"id": "...", "seq": 3, "sender": "ann", "name": "Ann", "kind": "text",
"text": "hi", "metadata": {"reply_to": 2}, "reactions": {"👍": ["support-bob"]}, "created_at": "..."}ข้อความที่แก้ไขจะคง seq เดิมและมี edited_at ข้อความที่ลบจะคงตำแหน่งไว้พร้อม deleted_at และไม่มีข้อความ แก้ไขหรือกดอีโมจิไม่ได้อีก (409) การอ่านแบบ after คืนเฉพาะข้อความใหม่กว่า ไคลเอนต์ที่กลับมาจึงอ่านข้อความที่แสดงอยู่ซ้ำ (last=n) เพื่อรับการแก้ไข การลบ และอีโมจิ การค้นหาจับคู่ส่วนใดก็ได้ของคำ ไม่สนตัวพิมพ์เล็กใหญ่และอักขระเต็มความกว้าง จึงใช้ได้กับภาษาจีน ญี่ปุ่น และเกาหลี ข้อความระบบบอกว่าเกิดอะไรขึ้น (เข้าร่วม โอนต่อ ปิด) มีเพียงเซิร์ฟเวอร์ของคุณที่ส่งได้ ไม่มีการพุชและไม่นับเป็นยังไม่อ่าน
สถานะอ่านแล้วและจำนวนที่ยังไม่อ่าน
| เมธอดและพาธ | เนื้อหา | ผลลัพธ์ |
|---|---|---|
POST /conversations/{id}/read | user_id, seq | {read_seq} |
ตำแหน่งที่สมาชิกอ่านถึงจะเดินหน้าเท่านั้นและไม่เกิน last_seq ผู้ส่งข้อความถือว่าอ่านแล้ว unread ในรายการบทสนทนาของผู้ใช้นับข้อความหลัง read_seq ที่ไม่ใช่ข้อความระบบ สมาชิกทุกคนได้รับ chat.read เมื่อ read_seq ของใครเดินหน้า
เบราว์เซอร์และแอป: โทเคนผู้ใช้
ไคลเอนต์เรียก Chat API เองได้ที่ /apps/APP_ID/chat/me พร้อม Authorization: Bearer <user token> โดยไม่ต้องมีพร็อกซีบนเซิร์ฟเวอร์ของคุณ โทเคนคือ JWT ที่ลงลายเซ็นด้วยซีเคร็ตของแอป (HS256, {sub, exp}, นานสุด 30 วัน) เซิร์ฟเวอร์ของคุณสร้างได้ด้วยไลบรารี JWT ใดก็ได้หรือด้วย POST /tokens:
| เมธอดและพาธ | เนื้อหา | ผลลัพธ์ |
|---|---|---|
POST /tokens | user_id, conversation_id (จำกัดโทเคนไว้ที่บทสนทนานั้น), join (เพิ่มผู้ใช้เข้าบทสนทนาเมื่อใช้ครั้งแรก), ttl (60–86400 วินาที) | 201 {token, expires_at} |
เมื่อมีโทเคน ไคลเอนต์แสดงรายการบทสนทนาของตน (GET /me/conversations) อ่าน ค้นหา ส่ง แก้ไขและลบข้อความของตัวเอง กดอีโมจิ ทำเครื่องหมายอ่านแล้ว และส่งสถานะกำลังพิมพ์ได้ ผู้ใช้คือ sub ของโทเคนเสมอ ไคลเอนต์สร้างบทสนทนา เปลี่ยนสมาชิก ตั้งค่าพุช ปิดเสียง หรือแบนไม่ได้ สิ่งเหล่านั้นอยู่ที่เซิร์ฟเวอร์ของคุณ ผู้ใช้แต่ละคนเขียนได้สูงสุด 2 ครั้งต่อวินาที และสูงสุด 10 ครั้งแบบต่อเนื่อง โทเคนที่มี conversation_id และ join เหมาะกับผู้เยี่ยมชมนิรนามของแชตซัพพอร์ต: เซิร์ฟเวอร์ของคุณสร้างบทสนทนา ตรวจสอบผู้เยี่ยมชม แล้วออกโทเคนอายุสั้นให้ ID ที่สร้างขึ้นเอง
ไฟล์แนบ
- เซิร์ฟเวอร์ของคุณขออัปโหลด:
POST /conversations/{id}/attachmentsพร้อมuser_id,name,content_typeและsize(สูงสุด 25 MB) คำตอบมีattachmentและupload(url,method,headers) - ไคลเอนต์อัปโหลดไฟล์ตรงไปที่
upload.urlภายใน 15 นาที ด้วยเฮดเดอร์เหล่านั้นทุกตัว - เซิร์ฟเวอร์ของคุณส่งข้อความพร้อม
attachments:id,nameและcontent_typeจากขั้นที่ 1 (สูงสุด 10 ไฟล์ต่อข้อความ และtextเว้นว่างได้)
ไฟล์แนบทุกไฟล์ที่อ่านจาก API หรืออีเวนต์มี url ที่ดาวน์โหลดได้ภายในหนึ่งชั่วโมง ไฟล์ที่อัปโหลดแต่ไม่ได้ส่งภายในหนึ่งวันจะถูกลบ และการลบข้อความหรือบทสนทนาจะลบไฟล์ของมันด้วย
พุชถึงสมาชิกที่ออฟไลน์
ข้อความใหม่จะถูกพุชผ่าน Hibira Push ของแอปไปยังสมาชิกที่ไม่ได้เชื่อมต่อ (push: "offline" ค่าเริ่มต้น) ไปยังสมาชิกทุกคนยกเว้นผู้ส่ง ("always") หรือไม่พุชเลย ("never") หัวเรื่องคือชื่อผู้ส่งและชื่อบทสนทนา (หรือ push_title) เนื้อหาคือ 180 ตัวอักษรแรกของข้อความ และ push_url จะเปิดเมื่อแตะ อุปกรณ์ลงทะเบียนด้วย SDK พุชที่เข้ากันได้กับ Beams ด้วย ID ผู้ใช้เดียวกัน push ในคำตอบบอกว่าพุชถึงสมาชิกกี่คน หรือทำไมไม่มีการพุช
การกลั่นกรอง
| เมธอดและพาธ | เนื้อหาหรือ query | ผลลัพธ์ |
|---|---|---|
PUT /moderation/filter | words (สูงสุด 500), action (mask หรือ reject) | {filter} |
POST /users/{user_id}/ban | reason, until (RFC 3339; เว้นไว้คือไม่มีกำหนด) | {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} ใหม่สุดก่อน |
ตัวกรองคำตรวจทุกข้อความใหม่หรือที่แก้ไข จับคู่ได้แม้อยู่กลางคำ ไม่สนตัวพิมพ์และอักขระเต็มความกว้าง จึงจับภาษาจีนและญี่ปุ่นได้ด้วย mask แทนส่วนที่ตรงด้วย * ส่วน reject ตอบ 422 และไม่เก็บอะไร ผู้ใช้ที่ถูกแบนได้ 403 เมื่อส่ง แก้ไข กดอีโมจิ และพิมพ์ในทุกบทสนทนาของแอป สมาชิกที่ถูกปิดเสียงได้ 403 เมื่อส่งและพิมพ์ในบทสนทนานั้นแต่ยังอ่านได้
อีเวนต์และเว็บฮุก
อีเวนต์ถูกส่งไปที่ #server-to-user-<user_id> ของสมาชิกแต่ละคนที่เกี่ยวข้อง และไปที่ watchers ของบทสนทนา แต่ละอีเวนต์นับเป็นหนึ่งข้อความในโควตารายวัน
| อีเวนต์ | ถึง | ข้อมูล |
|---|---|---|
chat.conversation | สมาชิกทุกคน เมื่อสร้างหรือเปลี่ยน หรือเพิ่มสมาชิก | {conversation} |
chat.message | สมาชิกทุกคน | {conversation_id, message} |
chat.message_updated | สมาชิกทุกคน หลังแก้ไข ลบ หรือกดอีโมจิ | {conversation_id, message} |
chat.typing | สมาชิกทุกคนยกเว้นคนที่กำลังพิมพ์ | {conversation_id, user_id, typing} |
chat.read | สมาชิกทุกคน | {conversation_id, user_id, read_seq} |
chat.left | สมาชิกที่ถูกนำออก | {conversation_id} |
chat.deleted | สมาชิกทุกคนของบทสนทนาที่ถูกลบ | {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));เซิร์ฟเวอร์ของคุณยังได้รับเว็บฮุก chat_message สำหรับทุกข้อความใหม่: channel คือ ID บทสนทนา user_id คือผู้ส่ง และ data คือ JSON {"conversation_id", "message"} เพิ่ม chat_message ในอีเวนต์ของเว็บฮุกหนึ่งของแอปเพื่อรับ
ขีดจำกัด
| ID บทสนทนา | 1–128 ตัวของ A-Z a-z 0-9 _ - = @ , . ; |
| ID ผู้ใช้ | กฎเดียวกับ ID ผู้ใช้ของ pusher.signin |
| สมาชิกต่อบทสนทนา | 100 |
| ข้อความ | 4,000 ตัวอักษร ห้ามว่าง |
| ชื่อบทสนทนาหรือผู้ส่ง | 100 ตัวอักษร |
metadata | ออบเจกต์ JSON ไม่เกิน 4,096 ไบต์ |
| ข้อความต่อการอ่าน | 200 |
| อีโมจิ | ตัวละ 1–32 ไบต์ ต่างกันได้ 20 แบบต่อข้อความ |
| ไฟล์แนบ | ไฟล์ละ 25 MB, 10 ไฟล์ต่อข้อความ |
การเขียนใช้ขีดจำกัดอัตรา HTTP API ของแอปร่วมกัน (เกินแล้วได้ 429)
ผู้ใช้งานรายเดือนและระยะเวลาเก็บ
ผู้ใช้นับเป็นผู้ใช้งานในเดือนนั้น (UTC) เมื่อส่งข้อความหรือทำเครื่องหมายอ่านแล้ว นับครั้งเดียวทุกแอปของบัญชี ทุกบัญชีมี 500 คนต่อเดือน แพ็กเสริม Chat เพิ่มเป็น 1,000, 5,000, 20,000 หรือ 60,000 คน (แพ็กเกจ) เมื่อเดือนนั้นเต็ม ผู้ใช้ที่ยังไม่ถูกนับจะได้ 429 เมื่อส่งและอ่านจนถึงเดือนถัดไป ผู้ใช้ที่ถูกนับแล้วใช้ต่อได้ GET /usage ตอบ {month, active_users, limit}
ข้อความแก้ไขได้เต็มที่ภายใน 30 วัน หลังจากนั้น บัญชีที่มีแพ็กเกจแบบชำระเงินหรือแพ็กเสริม Chat จะเก็บไว้ในคลังที่ API ยังคืนให้ (อ่านอย่างเดียว) ส่วนแพ็กเกจ Free ที่ไม่มีแพ็กเสริมจะถูกลบ
ใช้งานจาก AI agent
MCP เซิร์ฟเวอร์ของ Hibira มีเครื่องมือ Chat API ให้ AI agent สำหรับเขียนโค้ดตั้งค่าและทดสอบแชตแทนคุณได้: create_conversation, send_message, list_conversations และ list_messages เครื่องมือเหล่านี้ทำงานกับแอปของคุณเองด้วยการตรวจสอบเดียวกับคำขอที่ลงลายเซ็น และต้องให้บัญชีเปิดใช้ Chat API แล้ว ปลั๊กอินสำหรับ agent ของ Claude Code, Codex, Cursor และอื่น ๆ มีสกิลที่เชื่อม Chat API เข้ากับโปรเจกต์ตามขั้นตอนนี้ หากต้องการหน้าสนทนาสำเร็จรูปสำหรับ React หรือ JavaScript ล้วน ดู @hibira-io/chat-ui