วิธีจัดการข้อความ LINE ที่ถูกแก้ไขด้วย Webhook message.updated
LINE เพิ่มอีเวนต์แก้ไขใน Messaging API เมื่อวันที่ 12 สิงหาคม 2026 เมื่อผู้ใช้แก้ไขข้อความตัวอักษรที่ส่งแล้วในแชตกลุ่มที่เข้าเงื่อนไขและมี LINE Official Account อยู่ในกลุ่ม LINE สามารถส่ง Webhook messageEdited ได้ ระบบกล่องข้อความทีมควรอัปเดตข้อความเดิม ไม่ใช่เพิ่มข้อความใหม่อีกหนึ่งรายการ สำหรับ UnifyPort อีเวนต์มาตรฐานที่ตรงกันคือ message.updated และใช้ data.message.id เดิมเป็นตัวเชื่อม
สรุปสำคัญ
- ชื่ออีเวนต์ของ LINE คือ
messageEditedส่วนชื่อมาตรฐานของ UnifyPort คือmessage.updated - ค้นหาข้อความเดิมด้วย messaging account, บทสนทนา และ
data.message.id - การแก้ไขคือการเปลี่ยนสถานะของข้อความ ไม่ควรนับเป็นข้อความขาเข้าใหม่
- ตรวจสอบลายเซ็น HMAC-SHA256 ก่อนแปลง JSON และเขียนข้อมูล
- การรับการแก้ไขจาก LINE ไม่ได้หมายความว่าสามารถสั่งแก้ไขข้อความ LINE ผ่าน UnifyPort ได้
สิ่งที่เปลี่ยนในแชตกลุ่ม LINE
หน้าข่าว Messaging API อย่างเป็นทางการ ของ LINE ระบุการอัปเดตเมื่อวันที่ 12 สิงหาคม 2026 ว่าผู้ใช้สามารถแก้ไขข้อความในแชตกลุ่มที่มี LINE Official Account และมีการเพิ่ม messageEdited ในออบเจ็กต์อีเวนต์ Webhook ส่วน Messaging API reference ปัจจุบันก็แสดง Edit event ในรายการอีเวนต์ Webhook แล้ว
สำหรับทีมในไทยที่ใช้ LINE เป็นช่องทางหลัก การเปลี่ยนแปลงนี้กระทบกล่องข้อความร่วม ไทม์ไลน์ CRM ดัชนีค้นหา และบริบทที่ส่งให้ AI หากลูกค้าแก้เลขคำสั่งซื้อ ที่อยู่ หรือรายละเอียดคำถาม แต่ระบบยังใช้ข้อความเก่า ระบบอัตโนมัติถัดไปอาจทำงานกับข้อมูลที่ล้าสมัย ในทางกลับกัน หากบันทึกข้อความที่แก้ไขเป็นข้อความใหม่ จำนวนข้อความจะซ้ำและไทม์ไลน์จะไม่ตรงกับ LINE
โมเดลที่ถูกต้องคือการอัปเดตสถานะของข้อความจากผู้ให้บริการรายการเดิม
จาก LINE messageEdited เป็น UnifyPort message.updated
Payload อย่างเป็นทางการของ LINE ใช้โครงสร้างเฉพาะแพลตฟอร์ม UnifyPort ทำให้การอัปเดตอยู่ใน envelope มาตรฐาน จึงใช้ handler เดียวกับข้อความที่ถูกแก้ไขจากผู้ให้บริการอื่นที่รองรับได้
{
"id": "evt_7f42c18a9d",
"type": "message.updated",
"provider": "line",
"account_id": "acc_8c21d0",
"occurred_at": "2026-08-22T09:15:30Z",
"data": {
"conversation": {
"id": "c8f2a4d91e",
"type": "group",
"title": "ฝ่ายช่วยเหลือคำสั่งซื้อ"
},
"sender": {
"id": "u71b9d420f",
"type": "user",
"name": "Jordan Lee"
},
"message": {
"id": "551842037194",
"text": "แก้ไข: หมายเลขคำสั่งซื้อคือ A1234",
"direction": "inbound",
"sent_at": "2026-08-22T09:12:04Z"
},
"event": {
"kind": "message_updated"
}
}
}
ID สองตัวมีหน้าที่ต่างกัน:
idระดับบนสุดระบุอีเวนต์ Webhook และใช้ตัดการส่งซ้ำdata.message.idระบุข้อความต้นฉบับที่มีเนื้อหาเปลี่ยนไป
ตรวจสอบความสามารถปัจจุบันได้ที่ ตารางความแตกต่างของอีเวนต์ Webhook ตามผู้ให้บริการ ตารางระบุว่า LINE รองรับ message.updated แต่ฟิลด์จริงอาจแตกต่างตามบัญชีต้นทางและสภาพแวดล้อมที่ใช้งาน
รวมข้อความแก้ไขโดยไม่สร้างรายการซ้ำ
อย่าถือว่า message ID ของผู้ให้บริการไม่ซ้ำกันทั่วทั้งระบบ ควรใช้คีย์ประกอบ:
(account_id, conversation_id, provider_message_id)
จากนั้นใช้การแก้ไขเป็น state transition ที่ทำซ้ำได้อย่างปลอดภัย:
- ตรวจสอบลายเซ็นจาก raw request body
- ตัดการส่งซ้ำด้วย Webhook event ID
- ค้นหาแถวเดิมด้วย
account_id,data.conversation.idและdata.message.id - แทนที่ข้อความปัจจุบันด้วย
data.message.text - บันทึก
occurred_atเป็นเวลาที่ระบบพบการแก้ไข - เก็บเวลารับครั้งแรกไว้ และเก็บ revision history แยกต่างหากหากต้องใช้ในการตรวจสอบ
- ตอบ 2xx หลังจากเขียนข้อมูลถาวรสำเร็จแล้ว
ตัวอย่าง Express ด้านล่างคงส่วนฐานข้อมูลเป็นนามธรรม เพื่อให้เห็นสัญญาอีเวนต์จริงอย่างชัดเจน
import crypto from 'crypto';
import express from 'express';
const app = express();
const secret = process.env.WEBHOOK_SIGNING_SECRET;
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
const timestamp = req.get('X-Device-Timestamp') || '';
const signature = req.get('X-Device-Signature') || '';
const expected = crypto.createHmac('sha256', secret)
.update(timestamp + '.')
.update(req.body)
.digest('hex');
const valid = signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
if (!valid) return res.sendStatus(401);
const event = JSON.parse(req.body.toString('utf8'));
if (await db.hasWebhookEvent(event.id)) return res.sendStatus(200);
if (event.type === 'message.updated') {
await db.applyMessageEdit({
accountId: event.account_id,
conversationId: event.data.conversation.id,
messageId: event.data.message.id,
text: event.data.message.text,
editedAt: event.occurred_at
});
}
await db.rememberWebhookEvent(event.id);
return res.sendStatus(200);
});
ดูรูปแบบสตริงสำหรับลายเซ็น เงื่อนไขการลองส่งใหม่ และข้อควรระวังเรื่องลำดับได้ใน คู่มือ Webhook delivery และ signature ส่วน บทเรียน HMAC และการป้องกันคำขอซ้ำเก่า อธิบาย timestamp และ idempotency เพิ่มเติม
เมื่อข้อความต้นฉบับหายไปหรือมาถึงผิดลำดับ
Webhook ไม่รับประกันลำดับการส่ง อีเวนต์แก้ไขอาจถึง worker ก่อนที่ข้อความต้นฉบับจะ commit เสร็จ หรือระบบรับอาจพลาดข้อความต้นฉบับในช่วงที่ออฟไลน์ อย่าสร้างรายการไทม์ไลน์ทั่วไปและอย่าเพิ่มสถิติขาเข้าทันที
ให้เก็บการอัปเดตไว้ชั่วคราวในตาราง pending ที่ใช้คีย์ข้อความประกอบ เมื่อ message.received ต้นฉบับมาถึง ให้ใช้ข้อความที่รออยู่ก่อนแสดงรายการ หากต้นฉบับไม่มาถึง ให้แสดงเป็นข้อมูลการแก้ไขที่ไม่สมบูรณ์เพื่อให้เจ้าหน้าที่ตรวจสอบ แทนการแสดงเป็นข้อความสมบูรณ์
แนวคิดแบบ state เดียวกันใช้กับ reaction ได้ อ่าน วิธีประมวลผล Message Reactions ใน Unified Webhook เพื่อแยกอีเวนต์ออกจากสถานะข้อความที่อีเวนต์นั้นเปลี่ยนแปลง
UnifyPort เหมาะกับจุดใด และมีข้อจำกัดอะไร
UnifyPort เหมาะกับทีมขนาดเล็กที่รับข้อความจาก LINE พร้อมกับ WhatsApp, Telegram, TikTok, Zalo หรือ X และต้องการสัญญาอีเวนต์แบบมีลายเซ็นเพียงรูปแบบเดียว อินเทอร์เฟซที่ไม่เป็นทางการนี้ช่วยลด parser เฉพาะแพลตฟอร์ม และให้ handler แยกทำงานด้วย message.updated
หากแอปเน้น LINE Official Account และต้องใช้ความสามารถเฉพาะของ LINE หรือ Payload ดั้งเดิม Messaging API อย่างเป็นทางการยังเหมาะกว่า นอกจากนี้ต้องแยกขอบเขตการทำงานให้ชัด: UnifyPort ทำให้การอัปเดตข้อความ LINE ที่รับเข้ามาเป็นมาตรฐานได้ แต่ปัจจุบัน POST /v1/messages/edit ยังไม่รองรับการแก้ไขข้อความขาออกสำหรับ LINE การรับการแก้ไขและการสั่งแก้ไขเป็นคนละความสามารถ
คำถามที่พบบ่อย
LINE messageEdited คืออะไร
เป็นอีเวนต์ Webhook อย่างเป็นทางการของ LINE Messaging API สำหรับการแก้ไขข้อความที่เข้าเงื่อนไข LINE ประกาศเพิ่มอีเวนต์นี้สำหรับแชตกลุ่มที่มี LINE Official Account เมื่อวันที่ 12 สิงหาคม 2026
ต้อง subscribe อีเวนต์ใดใน UnifyPort
ใช้ message.updated หรือใช้ "*" หาก endpoint ตั้งใจรับอีเวนต์มาตรฐานสาธารณะทั้งหมด สำหรับ production filter ควรระบุชื่ออีเวนต์เต็มอย่างชัดเจน
ข้อความ LINE ที่แก้ไขควรสร้างรายการใหม่ในกล่องข้อความหรือไม่
ไม่ควร ให้ใช้ data.message.id ค้นหาและอัปเดตข้อความเดิม หากต้องเก็บหลักฐานการเปลี่ยนแปลง ให้บันทึก revision แยกต่างหาก
แก้ไขข้อความ LINE ผ่าน UnifyPort ได้หรือไม่
ปัจจุบันยังไม่ได้ ตาราง provider actions ยังไม่ระบุการรองรับ outbound edit สำหรับ LINE บทความนี้ครอบคลุมเฉพาะการรับและรวมอีเวนต์แก้ไข
ขั้นตอนถัดไป
ตรวจสอบ ตารางอีเวนต์ Webhook แยกตามผู้ให้บริการ เพิ่ม message.updated ใน subscription และทดสอบทั้งการอัปเดตซ้ำกับกรณีอีเวนต์มาผิดลำดับก่อนเปิดใช้กับกล่องข้อความ production
แหล่งข้อมูลอย่างเป็นทางการ
ตรวจสอบเมื่อวันที่ 22 สิงหาคม 2026:
เปลี่ยนการเชื่อมต่อข้อความให้เป็น pipeline ผลิตภัณฑ์ที่เสถียร
เริ่มจากการส่งผ่าน API เดียว แล้วส่งข้อความขาเข้าทั้งหมดกลับสู่ระบบธุรกิจของคุณด้วย event มาตรฐาน