จัดการสถานะส่งถึงและอ่านแล้วแบบหลายข้อความด้วย UnifyPort
เหตุการณ์ยืนยันการส่งถึงหรือการอ่านของ UnifyPort อาจครอบคลุมหลายข้อความ หากมีข้อมูลแบบชุด ให้ประมวลผลทุก ID ใน data.message.ids; สำหรับข้อความเดียวให้ใช้ data.message.id เก็บเหตุการณ์ยืนยันแยกจากเนื้อหาข้อความเพื่อรองรับกรณีที่เหตุการณ์มาถึงก่อน การรับคำขอส่ง สถานะจากผู้รับ และสถานะอ่านแล้วในกล่องข้อความของทีม เป็นหลักฐานคนละประเภท ไม่ควรใช้ธง “สำเร็จ” ร่วมกัน
ประเด็นสำคัญ
- จับคู่ภายใน workspace ผู้ให้บริการ บัญชีรับส่งข้อความ และบทสนทนา ไม่ใช่ด้วย ID ข้อความเพียงอย่างเดียว
- เก็บเวลาที่ผู้ให้บริการรายงานแยกจากเวลาที่ webhook มาถึง
- เหตุการณ์ส่งถึงที่มาช้าต้องไม่ลบหลักฐานว่าอ่านแล้ว
- การไม่มีสถานะยืนยันหมายถึงยังไม่ทราบ ไม่ใช่สิทธิ์ให้ส่งซ้ำ
ตรวจขอบเขตของชุดก่อนเปลี่ยนสถานะบนหน้าจอ
ข้อกำหนดเหตุการณ์มาตรฐาน กำหนดให้ message.delivered หมายถึงส่งถึงอุปกรณ์ของผู้รับ และ message.read หมายถึงผู้รับอ่านแล้ว ฟิลด์สำหรับชุดข้อความคือ data.message.ids หากอัปเดตแค่ id จะตกหล่นข้อความที่เหลือ
| หลักฐาน | ยืนยันอะไร | ไม่ได้ยืนยันอะไร |
|---|---|---|
ผลส่งที่มี status: accepted | รับคำขอแล้ว | ส่งถึงหรืออ่านแล้ว |
message.delivered | ข้อความที่ระบุส่งถึงแล้ว | ผู้รับอ่านแล้ว |
message.read | ข้อความที่ระบุถูกอ่านแล้ว | ปิดงานบริการแล้ว หรือทุกคนในกลุ่มอ่านแล้ว |
| สถานะอ่านของบทสนทนาฝั่งบัญชี | สถานะรายการแชตของบัญชีที่เชื่อมต่อ | สถานะยืนยันจากผู้รับ |
แถวสุดท้ายเป็นเรื่องของขั้นตอนอ่าน/ยังไม่อ่านในกล่องข้อความร่วม อย่าเรียกคำสั่งทำเครื่องหมายบทสนทนาว่าอ่านแล้วเพื่อแก้การขาดเหตุการณ์ยืนยันของข้อความขาออก
ตัวอย่างย่อนี้ใช้ฟิลด์จากเอกสาร message.read เพื่ออธิบายรูปแบบ ไม่ใช่เหตุการณ์จริงของลูกค้า:
{
"id": "evt_2f9c1a4b7e",
"type": "message.read",
"provider": "whatsapp",
"account_id": "acc_8c21d0",
"occurred_at": "2026-06-08T12:35:10Z",
"data": {
"conversation": { "id": "8613912345678", "type": "user" },
"sender": { "id": "8613912345678", "type": "user" },
"message": {
"id": "wamid.HBgM",
"ids": ["wamid.HBgM", "wamid.HBgN"],
"read_at": "2026-06-08T12:35:10Z"
}
}
}
เหตุการณ์นี้ครอบคลุมสองข้อความในรายการ ไม่ได้ยืนยันว่าข้อความก่อนหน้าทั้งหมดถูกอ่านแล้ว แม้ ID จะดูเหมือนตัวเลข ก็อย่าอนุมานเป็นช่วงต่อเนื่อง
เก็บหลักฐานก่อนสร้างป้ายสถานะ
การออกแบบที่แนะนำมีสองชั้น: บันทึกเหตุการณ์ที่ตรวจลายเซ็นแล้วอย่างถาวร และมุมมองสถานะรายข้อความ ทั้งสองเป็นโครงสร้างของแอป ไม่ใช่ฟิลด์ใหม่ของ UnifyPort
- เพิ่มชื่อเหตุการณ์ยืนยันทั้งสองในรายการสมัครรับ โดยรักษาเหตุการณ์อื่นที่จำเป็นและการตั้งค่าลายเซ็นไว้
- ทำตามข้อกำหนดการส่ง webhook ใช้
signing_secretตรวจ HMAC-SHA256 ของ timestamp ต่อด้วยจุดและ raw body พร้อมตรวจความสดใหม่ของ timestamp ที่ลงลายเซ็น - เก็บเหตุการณ์ที่ตรวจแล้วอย่างถาวรก่อนตอบ 2xx บันทึกเหตุการณ์และงานถาวรแบบ atomic หรือบันทึกการอัปเดตมุมมองกับข้อมูลกันซ้ำใน transaction เดียวกัน
- แยกชุดเป็นบันทึกรายข้อความ เก็บบริบท workspace,
provider,account_id,data.conversation.id, ID เหตุการณ์ และตัวตนผู้ส่งที่มีอยู่ - เก็บ
occurred_at,read_atหรือdelivered_atของผู้ให้บริการ และเวลารับของแอปแยกกัน เวลายืนยันยังมีสำเนาในฟิลด์ชื่อเดียวกันที่ระดับdataถ้าไม่มีเวลาให้คงไว้ว่าไม่ทราบ อย่าใช้เวลารับแทนเวลาของผู้ให้บริการ
JavaScript ต่อไปนี้ดึงเฉพาะขอบเขตข้อความจากเหตุการณ์ที่ตรวจลายเซ็นแล้ว ไม่ใช่ตัวรับหรือระบบฐานข้อมูลที่สมบูรณ์:
function receiptMessageIds(event) {
if (!['message.delivered', 'message.read'].includes(event.type)) return [];
const message = event.data?.message;
const ids = message?.ids === undefined ? [message?.id] : message.ids;
if (!Array.isArray(ids) || ids.length === 0 ||
ids.some(id => typeof id !== 'string' || id.length === 0)) {
throw new Error('Receipt scope needs review');
}
return [...new Set(ids)];
}
หากข้อมูลชุดผิดรูปแบบ อย่าสลับไปใช้ ID เดี่ยวโดยเงียบ ๆ ให้เก็บเหตุการณ์ไว้ตรวจสอบแทนการเดาขอบเขต
รวมหลักฐานโดยไม่สร้างข้อสรุปขึ้นเอง
เก็บการสังเกตว่าส่งถึงและอ่านแล้วแยกกัน ถ้าเหตุการณ์อ่านแล้วมาก่อน สามารถแสดงว่า “พบหลักฐานการอ่าน” โดยไม่สร้าง delivered_at ขึ้นเอง เหตุการณ์ส่งถึงที่ตามมาคือหลักฐานเพิ่มเติม ไม่ควรลดสถานะหน้าจอกลับเป็น “ส่งถึงแล้ว” และเหตุการณ์ซ้ำต้องไม่สร้างการแจ้งเตือนซ้ำ
ถ้ายังไม่มีเนื้อหาข้อความ ให้เก็บเหตุการณ์ยืนยันตามตัวตนข้อความแบบมีขอบเขต แล้วเชื่อมเมื่อมีรายการที่ตรงกัน อย่าสร้างข้อความขาเข้าหรือเพิ่มจำนวนข้อความในกล่องจากเหตุการณ์ยืนยันเพียงอย่างเดียว ใช้ occurred_at กับ ID เหตุการณ์เพื่อกำหนดลำดับที่แน่นอนได้ แต่ไม่ควรให้สถานะที่มาถึงล่าสุดเขียนทับทุกอย่าง
เมื่อส่งข้อความ ให้เก็บ message_id และ provider_ref ที่ตอบกลับคู่กับรายการดำเนินการภายใน ก่อนจับคู่เหตุการณ์ ต้องยืนยันว่าตัวระบุใดตรงกับข้อความของผู้ให้บริการ ชื่อฟิลด์ที่ต่างกันไม่ได้รับประกันว่าค่าจะเท่ากันเสมอ เหตุการณ์ที่จับคู่ไม่ได้ควรเข้าคิวตรวจสอบ ไม่ใช่ผูกกับข้อความที่มีเวลาใกล้ที่สุด เก็บตัวตนผู้ส่งที่มีอยู่ และอย่าขยายหลักฐานหนึ่งรายการเป็น “ทุกคนอ่านแล้ว”
คู่มือแก้ปัญหาการส่งสื่อ ครอบคลุมแหล่งไฟล์และการรับคำขอ ส่วนการจัดการสถานะยืนยันเป็นอีกชั้นหนึ่ง timeout หรือการไม่มีเหตุการณ์ต้องไม่ทำให้ส่งข้อความใหม่โดยอัตโนมัติ
ขอบเขตการรองรับ LINE และกรณีทดสอบ
UnifyPort เป็นอินเทอร์เฟซที่ไม่เป็นทางการ ตารางเหตุการณ์รายผู้ให้บริการ อธิบายการรองรับของ parser ไม่ใช่การรับประกันว่าทุกบัญชีหรือทุกระบบจะส่งเหตุการณ์ แม้กล่องข้อความของทีมจะใช้ LINE ก็ควรตรวจผู้ให้บริการที่เลือกก่อนสัญญาว่าจะแสดงสถานะส่งถึงได้ การไม่มีเหตุการณ์ไม่ได้พิสูจน์ว่ายังไม่อ่าน ส่งไม่ถึง หรือถูกบล็อก และไม่มีการรับประกันว่าจะส่ง payload ที่พลาดไปให้ใหม่
กรณีทดสอบที่แนะนำ: ชุดสองข้อความ ข้อความเดียว การส่งซ้ำ อ่านมาก่อนส่งถึง เหตุการณ์มาก่อนเนื้อหา ID เหมือนกันในคนละบัญชี ข้อมูลชุดผิดรูปแบบ และไม่มีเหตุการณ์เลย ตรวจว่ามีเพียง ID ที่ระบุชัดเจนเท่านั้นที่เปลี่ยน และไม่มีกรณีใดสั่งส่งซ้ำ นี่คือการทดสอบที่ควรทำ ไม่ใช่ผลทดสอบที่เกิดขึ้นแล้ว
คำถามที่พบบ่อย
ควรใช้ id หรือ ids?
ใช้ ids เมื่อมีชุดที่ถูกต้องและไม่ว่าง มิฉะนั้นใช้ id เดี่ยว ขอบเขตที่ไม่ถูกต้องต้องเข้าสู่การตรวจสอบ
ใช้เหตุการณ์อ่านแล้วเติม delivered_at ได้ไหม?
ไม่ได้ แสดงหลักฐานการอ่านได้ แต่ห้ามสร้างเวลาส่งถึงของผู้ให้บริการขึ้นเอง
ไม่มีเหตุการณ์ยืนยันแล้วตั้งเป็นส่งล้มเหลวได้ไหม?
ไม่ได้ด้วยเหตุผลนี้เพียงอย่างเดียว คงสถานะไม่ทราบ แล้วตรวจการรองรับ การสมัครรับ เส้นทางรับเหตุการณ์ และการจับคู่ ID
ขั้นต่อไปและแหล่งอ้างอิง
เริ่มจากเอกสารสถานะส่งถึง สร้างที่เก็บหลักฐานตามขอบเขตข้อความก่อนเพิ่มป้ายสถานะบนหน้าจอ
ตรวจเอกสารผลิตภัณฑ์เมื่อ 2026-11-06:
เปลี่ยนการเชื่อมต่อข้อความให้เป็น pipeline ผลิตภัณฑ์ที่เสถียร
เริ่มจากการส่งผ่าน API เดียว แล้วส่งข้อความขาเข้าทั้งหมดกลับสู่ระบบธุรกิจของคุณด้วย event มาตรฐาน