วิธีซิงก์สถานะอ่านแล้วและยังไม่อ่านของ WhatsApp ในกล่องข้อความร่วม
กล่องข้อความร่วมของ WhatsApp ไม่ควรทำเครื่องหมายบทสนทนาว่าอ่านแล้วทันทีที่ Webhook มาถึง ควรอัปเดตเมื่อทีมรับงานหรือปิดงานจริง ด้วย UnifyPort คุณเรียกคำสั่งอ่านแล้วโดยส่ง conversation_id ได้ หากต้องการส่งสถานะการอ่านถึงข้อความ WhatsApp รายการหนึ่ง ต้องส่งทั้ง ID ข้อความและ ID ผู้ส่งพร้อมกัน ส่วนงานที่ต้องกลับมาติดตามให้ทำเครื่องหมายว่ายังไม่อ่าน
สรุปสำคัญ
- คำสั่งอ่านแล้วและยังไม่อ่านระดับบทสนทนารองรับ WhatsApp เท่านั้นในขณะนี้ คู่ผู้ให้บริการและคำสั่งที่ไม่รองรับจะตอบ
501 unsupported_by_provider POST /v1/accounts/{account_id}/conversations/readต้องมีconversation_idและเลือกกำหนดข้อความปลายทางได้up_to_message_idกับup_to_message_sender_idต้องมาด้วยกัน หากส่งเพียงค่าเดียวจะได้400 invalid_request- คำสั่งทำเครื่องหมายว่ายังไม่อ่านต้องใช้เพียง
conversation_id - เก็บสถานะผู้รับผิดชอบ รอติดตาม และปิดงานไว้ในระบบของคุณเอง สถานะอ่านแล้วฝั่ง WhatsApp เป็นเพียงภาพสะท้อน ไม่ใช่ฐานข้อมูลงานบริการทั้งหมด
แยกความหมายของ “อ่านแล้ว” สามแบบ
กล่องข้อความร่วมที่เสถียรต้องแยกสถานะเหล่านี้ออกจากกัน
- สถานะคิวของทีม เช่น งานใหม่ มอบหมายแล้ว รอ หรือเสร็จสิ้น ซึ่งแอปของคุณเป็นผู้กำหนด
- สถานะรายการแชตของบัญชี WhatsApp ที่เชื่อมต่อ คืออ่านแล้วหรือยังไม่อ่าน เปลี่ยนได้ด้วย API ทำเครื่องหมายบทสนทนาว่าอ่านแล้ว และ API ทำเครื่องหมายว่ายังไม่อ่าน
- ใบตอบรับจากผู้รับ อีเวนต์
message.readหมายถึงผู้รับอ่านข้อความที่บัญชีส่งออกไปหนึ่งรายการหรือหลายรายการ ไม่ได้หมายความว่าเจ้าหน้าที่เปิดเคสขาเข้าแล้ว
เมื่อการตั้งค่าบทสนทนาในบัญชีเปลี่ยน UnifyPort สามารถแมปอีเวนต์ conversation.updated ได้ โดย data.conversation.id ระบุแชต และการเปลี่ยนสถานะการอ่านอาจอยู่ใน data.read ใช้อีเวนต์นี้เพื่อตรวจสอบสถานะ แต่ยังต้องบันทึกว่าใครรับงาน ปิดงานเมื่อใด และเปิดงานใหม่เพราะอะไรในฐานข้อมูลของคุณ
ก่อนนำอีเวนต์ไปใช้ ให้ตรวจสอบลายเซ็นจาก raw body และจัดการการส่งซ้ำแบบ idempotent อ่านขอบเขตตัวรับได้ใน คู่มือ Webhook HMAC การป้องกัน replay และการ retry หาก endpoint ต้องการเฉพาะอีเวนต์กล่องข้อความ ให้สมัครเฉพาะรายการที่จำเป็นตาม บทแนะนำตัวกรองอีเวนต์ Webhook
กำหนดจังหวะเปลี่ยนสถานะฝั่ง WhatsApp
อย่าทำเครื่องหมายว่าอ่านแล้วทุกครั้งที่มี Webhook ขาเข้า เพราะคิวที่ยังไม่มีคนดูจะดูเหมือนว่าง ใช้นโยบายที่ชัดเจนแทน
| การทำงานของทีม | สถานะคิวภายใน | คำสั่ง WhatsApp |
|---|---|---|
| บันทึกข้อความขาเข้าแล้ว | new | ไม่ทำอะไร |
| เจ้าหน้าที่รับบทสนทนา | assigned | ทำเครื่องหมายถึงข้อความที่รับ หากต้องการ |
| เจ้าหน้าที่ปิดบทสนทนา | resolved | ทำเครื่องหมายทั้งบทสนทนาว่าอ่านแล้ว |
| เจ้าหน้าที่กำหนดติดตาม | waiting | ทำเครื่องหมายว่ายังไม่อ่าน |
| ระบบอัตโนมัติล้มเหลวก่อนมอบหมาย | new | ไม่ทำอะไร |
การแยกนี้ยังป้องกันไม่ให้การรีเฟรชเบราว์เซอร์ การ retry ของ Webhook หรือพรีวิวเบื้องหลังล้างงานค้างโดยไม่ตั้งใจ
ทำเครื่องหมายบทสนทนา WhatsApp ว่าอ่านแล้ว
ส่ง conversation_id ใน JSON body ไม่ใช่ URL path เพราะ ID จากผู้ให้บริการอาจมีอักขระอย่าง @ หรือ :
ทำเครื่องหมายทั้งบทสนทนาว่าอ่านแล้ว:
curl -X POST "https://api.unifyport.ai/v1/accounts/$UNIFYPORT_ACCOUNT_ID/conversations/read" \
-H "X-Api-Key: $UNIFYPORT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"conversation_id": "8613912345678@s.whatsapp.net"
}'
หากต้องการส่งสถานะการอ่านถึงข้อความขาเข้าที่ระบุ ให้คัดลอก ID ทั้งสามจากอีเวนต์ message.received เดียวกัน
{
"conversation_id": "120363041234567890@g.us",
"up_to_message_id": "CURRENT-MESSAGE-ID",
"up_to_message_sender_id": "8613912345678@lid"
}
สำหรับกลุ่ม up_to_message_sender_id ต้องเป็น data.sender.id ที่ตรงกับข้อความนั้น ห้ามคำนวณจาก conversation ID หากไม่ต้องการสถานะระดับข้อความ ให้ละทั้งสองฟิลด์ up_to_message_*
Node.js helper นี้ตรวจสอบคู่ฟิลด์ก่อนเรียก API:
const apiBase = 'https://api.unifyport.ai/v1';
async function setWhatsAppReadState({ accountId, conversationId, unread, message }) {
const action = unread ? 'unread' : 'read';
const body = { conversation_id: conversationId };
if (!unread && message) {
if (!message.id || !message.senderId) {
throw new Error('message.id and message.senderId must be supplied together');
}
body.up_to_message_id = message.id;
body.up_to_message_sender_id = message.senderId;
}
const response = await fetch(
`${apiBase}/accounts/${encodeURIComponent(accountId)}/conversations/${action}`,
{
method: 'POST',
headers: {
'X-Api-Key': process.env.UNIFYPORT_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}
);
if (!response.ok) {
const failure = await response.json();
throw new Error(`${response.status} ${failure.error?.code ?? 'unknown_error'}`);
}
return response.json();
}
ใน event handler ที่ตรวจสอบลายเซ็นแล้ว ให้ใช้ฟิลด์ตามเอกสารโดยตรง
await setWhatsAppReadState({
accountId: event.account_id,
conversationId: event.data.conversation.id,
unread: false,
message: {
id: event.data.message.id,
senderId: event.data.sender.id
}
});
ทำเครื่องหมายว่ายังไม่อ่านเพื่อกลับมาติดตาม
คำสั่งยังไม่อ่านสั้นกว่า:
await setWhatsAppReadState({
accountId: event.account_id,
conversationId: event.data.conversation.id,
unread: true
});
ใช้เมื่อทีมเปิดงานกลับมาอย่างชัดเจน อย่าใช้สถานะยังไม่อ่านของผู้ให้บริการเป็นระบบเตือนเพียงอย่างเดียว ควรเก็บผู้รับผิดชอบ สถานะกำหนดเวลา และเหตุผลไว้ในคิวภายในด้วย
ตรวจสอบสถานะโดยไม่สร้างลูป
หลังแอปเรียกคำสั่งบทสนทนา อาจมี conversation.updated ที่สอดคล้องกันส่งเข้า Webhook เก็บบันทึกการดำเนินการที่เริ่มจากระบบของคุณ เพื่อให้อีเวนต์ที่ตามมาใช้ยืนยันสถานะ ไม่ใช่เรียกคำสั่งเดิมซ้ำ
ลำดับที่ปลอดภัยคือ:
- บันทึก
message.receivedแบบ idempotent - อัปเดตสถานะเคสภายใน transaction
- เรียกคำสั่งเปลี่ยนสถานะฝั่งผู้ให้บริการ
- บันทึกว่าสำเร็จหลัง API ตอบ
{ "data": { "ok": true } } - ใช้
conversation.updatedเป็นการยืนยันหรือการเปลี่ยนจากบัญชีที่เชื่อมต่อ - หากไม่แน่ใจ ให้เรียก Get conversation สำหรับบทสนทนานั้นและเปรียบเทียบ
unread_count
ก่อนเปิดปุ่มควบคุมนี้ให้ช่องทางอื่น ตรวจสอบ ตารางคำสั่งที่รองรับตามผู้ให้บริการ เส้นทาง API แบบเดียวกันไม่ได้แปลว่าทุกผู้ให้บริการรองรับทุกคำสั่ง
ข้อจำกัดและทางเลือก
หากงานต้องใช้ความสามารถธุรกิจที่ผ่านการรับรอง เทมเพลตข้อความทางการ หรือการกำกับดูแลแบบเนทีฟ เส้นทางทางการอาจเหมาะกว่า อินเทอร์เฟซไม่เป็นทางการของ UnifyPort เหมาะกับเวิร์กโฟลว์ข้อความของบัญชีทั่วไป แต่ไม่ได้ทำให้ทุกช่องทางมีความสามารถเหมือนกันทั้งหมด
คำสั่งอ่านแล้ว/ยังไม่อ่านในบทความนี้รองรับเฉพาะ WhatsApp ในขณะนี้ สำหรับทีมไทยที่ใช้ LINE เป็นช่องทางหลัก ให้เก็บสถานะคิว LINE ในระบบของคุณและซ่อนปุ่มเฉพาะ WhatsApp นี้ อย่ามอง 501 unsupported_by_provider เป็นข้อผิดพลาดชั่วคราวที่ควร retry ต่อเนื่อง
คำถามที่พบบ่อย
เมื่อรับ message.received แล้ว แชตจะถูกทำเครื่องหมายว่าอ่านแล้วอัตโนมัติหรือไม่
ไม่ การรับและบันทึกอีเวนต์ไม่ควรล้างคิว ให้เรียก endpoint อ่านแล้วเมื่อถึงขั้นตอนที่ทีมกำหนดเท่านั้น
message.read ต่างจากการทำเครื่องหมายบทสนทนาว่าอ่านแล้วอย่างไร
message.read เป็นอีเวนต์ใบตอบรับว่าผู้รับอ่านข้อความที่ส่งออกไป ส่วนคำสั่งระดับบทสนทนาเปลี่ยนสถานะรายการแชตในบัญชีที่เชื่อมต่อ
ส่งแค่ up_to_message_id ได้หรือไม่
ไม่ได้ ต้องส่งพร้อม up_to_message_sender_id หรือไม่ก็ละทั้งสองฟิลด์เพื่อทำเครื่องหมายทั้งบทสนทนาว่าอ่านแล้ว
ใช้คำสั่งเดียวกันกับ Telegram, LINE, TikTok, Zalo และ X ได้หรือไม่
ยังไม่ได้ ตารางรองรับระบุว่าคำสั่งอ่านแล้วและยังไม่อ่านระดับบทสนทนาเป็นของ WhatsApp เท่านั้น คู่ที่ไม่รองรับจะตอบ 501 unsupported_by_provider
ขั้นตอนต่อไป
เริ่มจาก API Reference สำหรับทำเครื่องหมายบทสนทนาว่าอ่านแล้ว แล้วเพิ่มคำสั่งยังไม่อ่านหลังจากกำหนดนโยบายเปิดงานใหม่ในระบบของคุณเรียบร้อย
แหล่งข้อมูลทางการ
ตรวจสอบเมื่อ 21 สิงหาคม 2026: