เมื่อ Event เกิดขึ้น MeeD จะส่ง HTTP POST ไปที่ endpoint_url ที่ตั้งค่าไว้ใน Webhook Subscription — รวมถึง /ping test event
หน้านี้อธิบาย:
ทุก Webhook Delivery จะมี Headers เหล่านี้
| Header | Description |
|---|---|
Content-Type | application/json |
X-MeeD-Event | Event type เช่น sales.order.completed |
X-MeeD-Webhook-Id | UUID ของ Webhook Subscription |
X-MeeD-Signature | sha256=<hmac_hex> — HMAC-SHA256 ของ Raw Request Body ที่ sign ด้วย signing_secret |
Payload เป็น JSON Object ที่มีโครงสร้างเดียวกันทุก Event Type
{
"event_type": "sales.order.completed",
"webhook_id": "a1b2c3d4-0000-0000-0000-000000000001",
"business_id": "e3d716b9-eed5-4128-a709-83927a832060",
"timestamp": "2026-06-16T10:30:00.000Z",
"data": { }
}
| Field | Type | Description |
|---|---|---|
| event_type | string | ประเภท Event เช่น sales.order.completed — ดูรายการทั้งหมดที่ Create Webhook |
| webhook_id | string (UUID) | UUID ของ Webhook Subscription ที่ trigger Event นี้ |
| business_id | string (UUID) | UUID ของธุรกิจ |
| timestamp | string (ISO 8601) | เวลาที่ Event เกิดขึ้น (UTC) |
| data | object | Record ที่เกี่ยวข้องกับ Event — เช่น sales.order.completed จะมีข้อมูล SalesOrder ครบถ้วน |
ตรวจสอบ X-MeeD-Signature ก่อนประมวลผล Payload ทุกครั้ง เพื่อยืนยันว่า Request มาจาก MeeD จริงและ Payload ไม่ถูกแก้ไขระหว่างทาง
signing_secret เป็น Keysha256= ด้านหน้าX-MeeD-Signature header โดยใช้ Constant-time Comparisonต้องใช้ crypto.timingSafeEqual — ไม่ใช่ === — เพื่อป้องกัน Timing Attack
signing_secret ได้รับเพียงครั้งเดียวตอนสร้าง Webhook — หากทำหาย ต้องสร้าง Webhook ใหม่
import crypto from 'crypto';
function verifySignature(
rawBody: string,
signingSecret: string,
signatureHeader: string
): boolean {
const expected =
'sha256=' +
crypto.createHmac('sha256', signingSecret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}
import express from 'express';
import crypto from 'crypto';
const app = express();
app.post(
'/webhooks/meed',
express.raw({ type: 'application/json' }), // ต้องใช้ raw() ไม่ใช่ json()
(req, res) => {
const signature = req.headers['x-meed-signature'] as string;
if (!verifySignature(req.body.toString(), process.env.WEBHOOK_SIGNING_SECRET!, signature)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body.toString());
const { event_type, data } = event;
switch (event_type) {
case 'sales.order.completed':
// handle completed order
break;
case 'inventory.stock.low':
// handle low stock alert
break;
}
res.status(200).send('ok');
}
);
ต้องใช้ express.raw() ไม่ใช่ express.json()
หาก Parse JSON ก่อน Body จะถูก Serialize ใหม่ทำให้ Hash ไม่ตรงและ Signature Verification ล้มเหลวทุกครั้ง
เมื่อ Endpoint ไม่ตอบกลับ 2xx MeeD จะ Retry ตาม Exponential Backoff โดยอัตโนมัติ
| Attempt | หลังจาก |
|---|---|
| 1 | ทันที (First delivery) |
| 2 | 5 นาที |
| 3 | 30 นาที |
| 4 | 2 ชั่วโมง |
| 5 | 12 ชั่วโมง |
หลัง Attempt ที่ 5 สถานะ Delivery จะเปลี่ยนเป็น DEAD — ตรวจสอบประวัติได้ที่ List Deliveries
webhook_id + timestamp หรือ data.id ก่อนประมวลผล200 ทันทีแม้ยังประมวลผลไม่เสร็จ แล้วทำงานหนักใน Background