Skip to content

Cấu trúc Webhook Events, JSON Payload & Chữ ký HMAC

This content is not available in your language yet.

Bài viết này cung cấp cấu trúc dữ liệu JSON Payload của các sự kiện Webhook mà TrolyPage gửi tới URL Callback của bạn khi có biến động dữ liệu thời gian thực — kèm cách xác thực chữ ký HMAC để đảm bảo request thực sự đến từ TrolyPage.

Để nhận sự kiện, bạn cần cho TrolyPage biết callback URL của bạn và chọn sự kiện muốn nhận («cần xác nhận UI/endpoint đăng ký»):

  1. Tạo endpoint HTTPS công khai trên server của bạn (vd https://api.yourshop.com/trolypage-webhook).
  2. Đăng ký URL này + chọn event trong trang cấu hình webhook của TrolyPage (hoặc qua Developer API nếu có endpoint cấu hình).
  3. Lấy Webhook Signing Secret (bí mật dùng ký chữ ký — xem mục 5).
  4. Server của bạn phải phản hồi HTTP 200 trong 5 giây cho mọi POST từ TrolyPage.

2. Sự kiện Tin nhắn mới đến (message_received)

Phần tiêu đề “2. Sự kiện Tin nhắn mới đến (message_received)”

Bắn ra khi có tin nhắn mới từ khách hàng gửi tới Facebook Messenger, Zalo OA hoặc Zalo Personal:

{
"event": "message_received",
"timestamp": 1774889400,
"tenant_id": 1042,
"data": {
"message_id": "msg_9f8a7b6c5d4e",
"channel": {
"type": "facebook_msg",
"id": "page_123456789"
},
"customer": {
"id": 8520,
"name": "Nguyễn Văn A",
"phone": "0912345678",
"avatar_url": "https://graph.facebook.com/12345/picture"
},
"content": {
"text": "Sản phẩm A giá bao nhiêu tiền shop?",
"attachments": []
},
"ai_handled": true
}
}

3. Sự kiện Đơn hàng cập nhật (order_updated)

Phần tiêu đề “3. Sự kiện Đơn hàng cập nhật (order_updated)”

Bắn ra khi đơn hàng đổi trạng thái (pendingconfirmedshippingcompleted):

{
"event": "order_updated",
"timestamp": 1774889450,
"tenant_id": 1042,
"data": {
"order_id": "DH-9821",
"status": "confirmed",
"total_amount": 350000,
"currency": "VND",
"payment_status": "paid",
"customer": {
"id": 8520,
"name": "Nguyễn Văn A",
"phone": "0912345678"
},
"items": [
{
"product_id": 101,
"product_name": "Áo thun Polo Cotton",
"quantity": 1,
"price": 350000
}
]
}
}

4. Sự kiện Thanh toán thành công (payment_completed)

Phần tiêu đề “4. Sự kiện Thanh toán thành công (payment_completed)”

Bắn ra khi hệ thống SePay / VietQR khớp mã đối soát tiền nộp ~0.5s:

{
"event": "payment_completed",
"timestamp": 1774889452,
"tenant_id": 1042,
"data": {
"transaction_id": "sp_tx_881923",
"order_id": "DH-9821",
"gateway": "sepay_vcb",
"amount_received": 350000,
"reference_code": "DH9821",
"status": "success"
}
}

5. Xác thực chữ ký Webhook (HMAC) — BẮT BUỘC

Phần tiêu đề “5. Xác thực chữ ký Webhook (HMAC) — BẮT BUỘC”

Mọi POST từ TrolyPage kèm header chứa chữ ký HMAC-SHA256 của body, ký bằng Webhook Signing Secret của bạn. Bạn phải verify trước khi xử lý để tránh request giả mạo.

Header chữ ký («cần xác nhận tên header + format»):

X-TrolyPage-Signature: sha256=75739d26e89c... # HMAC-SHA256 của raw body

Verify bằng Node.js:

import crypto from "node:crypto";
function verifyTrolyPageWebhook(rawBody, signatureHeader, signingSecret) {
const expected = crypto
.createHmac("sha256", signingSecret)
.update(rawBody, "utf8")
.digest("hex");
const received = signatureHeader.replace(/^sha256=/, "");
// Dùng timingSafeEqual để chống timing attack
const a = Buffer.from(expected, "hex");
const b = Buffer.from(received, "hex");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Verify bằng PHP:

function verifyTrolyPageWebhook(string $rawBody, string $signatureHeader, string $signingSecret): bool {
$expected = hash_hmac('sha256', $rawBody, $signingSecret);
$received = preg_replace('/^sha256=/', '', $signatureHeader);
return hash_equals($expected, $received); // hash_equals chống timing attack
}

6. Yêu cầu phản hồi HTTP 200 & Retry Schedule

Phần tiêu đề “6. Yêu cầu phản hồi HTTP 200 & Retry Schedule”
  • Máy chủ của bạn phải trả HTTP 200 OK trong vòng 5 giây.
  • Nếu trả mã lỗi (4xx/5xx) hoặc timeout > 5s → sự kiện vào Retry Queue với Exponential Backoff.

Lịch retry dự kiến («cần xác nhận số chính xác»):

Lần thử Độ trễ sau lần trước
1 (retry đầu) ~1 phút
2 ~5 phút
3 ~30 phút
4 ~2 giờ
5 (cuối) ~12 giờ

Sau ~24 giờ vẫn fail → sự kiện vào Dead-letter («cần xác nhận có DLQ + cách xem/khôi phục») và TrolyPage báo qua Trung tâm thông báo.