Cách WooCommerce gửi webhook

Lượt gửi chờ Action Scheduler trên WP-Cron, chỉ đi khi có trang được tải. Hơn năm lần thất bại liên tiếp vô hiệu hóa webhook. Định dạng và code xác minh Node.

Hành vi gửi

Lấy từ tài liệu của chính hãng, kiểm tra lần cuối 2026-08-06. Hãng không nêu con số nào thì bảng này cũng không ghi.

Thời hạn phản hồihãng không công bố

Lượt gửi được đưa vào hàng đợi của Action Scheduler và do WP-Cron kích hoạt, nên chỉ đi khi có trang được tải tiếp theo, không phải lúc sự kiện xảy ra

Thử lạihãng không công bố
Ngừng gửiWebhook bị vô hiệu hóa sau hơn năm lần gửi thất bại liên tiếp
Nguồnhttps://woocommerce.com/document/webhooks/

Chữ ký

Kiểm chứng bằng một bộ xác minh chạy thật, có bộ test chứng minh, chứ không đọc từ tài liệu. Kiểm chứng lần cuối 2026-08-20.

Thuật toánHMAC-SHA256
Payload được kýraw body
Encodingbase64
Headerx-wc-webhook-signature
Dung saikhông quy định

Xác minh

Dùng raw body của request, đúng từng byte, trước mọi bước parse JSON. Mọi cơ chế trên trang này đều hỏng ngay khi framework serialize lại payload.

const crypto = require("node:crypto");

// base64(HMAC-SHA256(secret, raw body))
const expected = crypto
  .createHmac("sha256", webhookSecret)
  .update(rawBody)
  .digest("base64");
const received = Buffer.from(req.headers["x-wc-webhook-signature"] ?? "");
const wanted = Buffer.from(expected);
// timingSafeEqual throws on a length mismatch, so check that first.
const valid =
  received.length === wanted.length && crypto.timingSafeEqual(received, wanted);

Những chỗ dễ vấp

Webhook không được bắn ra lúc đơn hàng phát sinh. Lượt gửi được đưa vào hàng đợi của Action Scheduler, vốn chạy trên WP-Cron, mà WP-Cron chỉ chạy khi có người tải trang tiếp theo. Với một cửa hàng vắng khách, đó là vài phút trễ có sẵn trước khi byte đầu tiên được gửi đi.

Hơn năm lần gửi thất bại liên tiếp sẽ vô hiệu hóa hẳn webhook, và chủ cửa hàng hiếm khi biết cho tới khi một hệ thống downstream lộ rõ dữ liệu cũ.

Đọc thêm

AnyHook đứng trước các endpoint nhận webhook từ WooCommerce: trả lời sau khoảng 1 giây, tự thử lại theo lịch riêng khi server của bạn ngừng hoạt động, và giữ mọi sự kiện để bạn phát lại được. Đổi một URL, giữ nguyên code.

Cách hoạt động →