วิธีประมวลผลรีแอ็กชันข้อความด้วย Webhook แบบรวม
การประมวลผลรีแอ็กชันควรเริ่มจากสมัครรับ message.reaction ตรวจสอบลายเซ็น Webhook กับ request body ดิบ แล้วใช้ data.message.target_message_id เป็น ID ของข้อความที่ถูกกดรีแอ็กชัน อีโมจิอยู่ใน data.event.reaction และค่าว่างหมายถึงผู้ใช้ลบรีแอ็กชัน ก่อนอัปเดตสถานะต้องตัดอีเวนต์ซ้ำด้วย ID ระดับบนสุด
สรุปสำคัญ
data.message.idระบุรีแอ็กชัน ไม่ใช่ข้อความต้นทางdata.message.target_message_idระบุข้อความที่ได้รับรีแอ็กชันdata.event.reactionเก็บอีโมจิ ส่วน""หมายถึงการลบ- ตรวจสอบ
X-Device-Signatureก่อนแปลง JSON - การรองรับต่างกันตามแพลตฟอร์ม ชื่ออีเวนต์ที่ถูกต้องไม่ได้แปลว่าทุกแพลตฟอร์มจะส่งอีเวนต์นั้น
ทำความเข้าใจ payload ของ message.reaction
UnifyPort ทำให้รีแอ็กชันอยู่ในอีเวนต์มาตรฐาน message.reaction ทีมที่ดูแล LINE และช่องทางอื่นในกล่องข้อความเดียวกันจึงกำหนดให้ 👍 หมายถึงรับทราบ ส่ง 👎 ไปให้เจ้าหน้าที่ตรวจ หรือเพียงแสดงอีโมจิปัจจุบันก็ได้ กฎเหล่านี้เป็นของแอป ส่วนอีเวนต์มีหน้าที่บอกว่าอะไรเปลี่ยนไป
เอกสารอีเวนต์ Webhook มาตรฐาน แสดงโครงสร้างหลักของ message.reaction ดังนี้:
{
"id": "evt_2f9c1a4b7e",
"type": "message.reaction",
"provider": "whatsapp",
"account_id": "acc_8c21d0",
"occurred_at": "2026-06-08T12:35:40Z",
"data": {
"conversation": { "id": "8613912345678", "type": "user" },
"sender": { "id": "8613912345678", "type": "user", "name": "Jordan Lee" },
"message": { "id": "wamid.HBgZ", "target_message_id": "wamid.HBgM" },
"event": { "kind": "message_reaction", "reaction": "👍" }
}
}
ID ทั้งสามทำหน้าที่ต่างกัน data.message.id คือเรคคอร์ดรีแอ็กชัน data.message.target_message_id ชี้ไปยังข้อความต้นทาง และ id ระดับบนสุดคืออีเวนต์ Webhook มาตรฐาน ในตัวอย่างนี้ต้องผูก 👍 กับ wamid.HBgM ไม่ใช่ wamid.HBgZ
เก็บสถานะปัจจุบัน ไม่ใช่แค่รายการอีเวนต์
บันทึกแบบ append-only เหมาะกับการตรวจสอบย้อนหลัง แต่หน้ากล่องข้อความมักต้องการสถานะล่าสุด คีย์สถานะที่ใช้งานได้ควรรวม provider, account_id, data.conversation.id, data.message.target_message_id และ data.sender.id
เมื่อ data.event.reaction ไม่ว่าง ให้บันทึกอีโมจิปัจจุบันของผู้ส่งต่อข้อความเป้าหมาย เมื่อเป็นสตริงว่าง ให้ลบสถานะนั้น อย่าเก็บค่าว่างเป็นรีแอ็กชันชนิดใหม่
ก่อนอัปเดต projection ให้บันทึกอีเวนต์ลงคิวหรือฐานข้อมูลที่ทนทาน และกำหนด unique constraint บน id ระดับบนสุด เพื่อไม่ให้การส่งซ้ำเปลี่ยนสถานะสองครั้ง หาก receiver เดิมรับเฉพาะข้อความขาเข้า ให้ใช้ คู่มือตัวกรองอีเวนต์ Webhook เพื่อเพิ่ม message.reaction โดยไม่ต้องเปลี่ยนเป็น wildcard ทันที
อัปเดตสถานะด้วย Node.js
โค้ดหลักต่อไปนี้ใช้ชื่อฟิลด์จริงจาก API reference ตัวอย่างใช้ Map เพื่ออธิบายแนวคิด ส่วนระบบจริงควรใช้ฐานข้อมูลที่รองรับ transaction และ unique constraint
const event = JSON.parse(rawBody.toString('utf8'));
if (event.type === 'message.reaction') {
const { conversation, sender, message, event: detail } = event.data;
if (!message?.target_message_id || typeof detail?.reaction !== 'string') {
throw new Error('Invalid message.reaction payload');
}
const key = [event.provider, event.account_id, conversation.id,
message.target_message_id, sender.id].join(':');
if (detail.reaction === '') reactionState.delete(key);
else reactionState.set(key, {
emoji: detail.reaction,
reactionMessageId: message.id,
occurredAt: event.occurred_at,
});
}
ต้องรันตรรกะนี้หลังตรวจสอบลายเซ็นเท่านั้น เมื่อ endpoint มี signing_secret ค่า X-Device-Signature คือ HMAC-SHA256 แบบเลขฐานสิบหกของ <X-Device-Timestamp>.<request body ดิบ> ห้ามแปลง JSON แล้ว serialize ใหม่ก่อนตรวจสอบ ดูขั้นตอนเต็มใน เอกสารการส่ง Webhook และลายเซ็น และดูเรื่องเวลา การส่งซ้ำ และ idempotency แบบถาวรใน คู่มือ HMAC และการประมวลผลซ้ำอย่างปลอดภัย
เลือก subscription และวิธีรับมือข้อผิดพลาด
consumer ที่รับเฉพาะรีแอ็กชันใช้การตั้งค่านี้ได้:
{
"subscribed_events": ["message.reaction"]
}
กล่องข้อความรวมมักสมัครทั้ง message.received และ message.reaction ส่วน "*" เหมาะกับ collector ทั่วไปที่พร้อมรับอีเวนต์มาตรฐานสาธารณะทุกชนิดเท่านั้น
ตอบ 2xx หลังรับอีเวนต์เข้าสู่ที่เก็บแบบทนทานแล้ว ปฏิเสธลายเซ็นที่ไม่ถูกต้อง และส่ง payload ที่โครงสร้างผิดไปยังเส้นทางข้อผิดพลาดที่ตรวจสอบได้ ก่อนใช้อีโมจิเป็นสัญญาณอนุมัติเพียงอย่างเดียว ให้ตรวจ ตารางอีเวนต์ Webhook แยกตามแพลตฟอร์ม
ตำแหน่งที่เหมาะกับ UnifyPort
UnifyPort เป็นอินเทอร์เฟซที่ไม่เป็นทางการซึ่งทำให้อีเวนต์จากแพลตฟอร์มที่รองรับอยู่ใน envelope เดียวกัน แอปจึงแยกตาม event.type และใช้ตรรกะสถานะชุดเดียวกันได้ในช่องทางที่มี message.reaction
การทำข้อมูลให้เป็นรูปแบบเดียวกันไม่ได้สร้างความสามารถที่แพลตฟอร์มต้นทางไม่มี หากรีแอ็กชันเป็นหลักฐานอนุมัติหรือข้อมูลที่ห้ามขาด ต้องตรวจสอบทุกแพลตฟอร์ม และเลือก API ทางการเมื่อสัญญาอีเวนต์เหมาะกับงานมากกว่า
คำถามที่พบบ่อย
ฟิลด์ใดคือ ID ของข้อความต้นทาง?
ใช้ data.message.target_message_id ส่วน data.message.id คือรีแอ็กชันเอง
จะรู้ได้อย่างไรว่าผู้ใช้ลบรีแอ็กชัน?
ตรวจ data.event.reaction ถ้าเป็นสตริงว่างแปลว่าลบ ถ้าไม่ว่างคืออีโมจิปัจจุบัน
ใช้ target_message_id ตัดรายการซ้ำได้ไหม?
ไม่ได้ หลายคนอาจกดรีแอ็กชันข้อความเดียวกัน และคนเดิมอาจเปลี่ยนอีโมจิ ใช้ id ระดับบนสุดตัดการส่งซ้ำ
ทุกแพลตฟอร์มส่ง message.reaction หรือไม่?
ไม่ ชื่ออีเวนต์ที่ถูกต้องกับการรองรับจริงเป็นคนละเรื่อง ต้องตรวจตารางอีเวนต์ก่อนใช้งานจริง
ขั้นตอนถัดไป
เปิด เอกสารสร้าง Webhook endpoint เพิ่ม message.reaction ใน subscribed_events ตั้งค่า signing_secret และทดสอบทั้งการเพิ่มกับการลบรีแอ็กชัน
แหล่งข้อมูล
แหล่งข้อมูลทางการ ตรวจสอบเมื่อ 20 สิงหาคม 2026: