Webhook là gì? Cách nhận và gửi webhook an toàn, kèm ví dụ thanh toán thật

Webhook là gì? Cách nhận và gửi webhook an toàn, kèm ví dụ thanh toán thật
22 Tháng 10, 2026 Lê Quốc Nghĩa 7 phút đọcHướng dẫn

Webhook là cách một phần mềm tự báo cho phần mềm khác ngay khi có chuyện xảy ra: có đơn hàng mới, khách vừa chuyển khoản, có người điền form trên website. Thay vì cứ vài phút lại hỏi "có gì mới không?", bạn đưa cho hệ thống kia một địa chỉ, và nó gửi dữ liệu tới địa chỉ đó đúng lúc sự kiện xảy ra. Bài này giải thích webhook bằng ngôn ngữ đời thường, cách nhận và gửi webhook an toàn, kèm ví dụ thật từ website opcaios.org.

Sơ đồ webhook: sự kiện xảy ra, hệ thống gửi POST có chữ ký tới địa chỉ của bạn
Một lần gửi webhook: có sự kiện → gửi dữ liệu kèm chữ ký → bên nhận kiểm tra rồi trả 200. Sơ đồ: OPCAIOS.

Webhook là gì?

Hãy so sánh hai cách chờ hàng giao tới:

  • Gọi điện hỏi mỗi 10 phút "hàng tới chưa?" — tốn công, và hàng tới giữa hai lần gọi thì bạn vẫn biết chậm.
  • Để lại số điện thoại, shipper tới nơi thì gọi bạn — không tốn công chờ, biết ngay lập tức.

Cách thứ nhất là gọi API theo kiểu hỏi liên tục (polling). Cách thứ hai là webhook: bạn đăng ký một địa chỉ URL, và khi sự kiện xảy ra, hệ thống kia gửi một yêu cầu HTTP POST chứa dữ liệu sự kiện tới địa chỉ đó.

Gọi API hỏi liên tục Webhook
Ai chủ động Bạn hỏi Hệ thống kia báo
Tốc độ biết tin Chậm tới một chu kỳ hỏi Gần như ngay lập tức
Tốn tài nguyên Nhiều lần hỏi không có gì mới Chỉ gửi khi có sự kiện
Bạn cần có Khoá API Một địa chỉ URL nhận được yêu cầu từ Internet

Webhook được dùng ở đâu?

  • Thanh toán: dịch vụ theo dõi chuyển khoản hoặc cổng thanh toán báo "đơn ABC đã trả tiền".
  • Bán hàng: sàn thương mại điện tử, phần mềm bán hàng báo có đơn mới, đơn huỷ.
  • Form và khách hàng: website báo có người để lại thông tin, CRM báo có khách mới.
  • Lập trình: GitHub báo có mã mới được đẩy lên để chạy kiểm thử và triển khai.
  • Nhắn tin: Zalo OA, Messenger, Telegram gửi tin nhắn khách hàng tới hệ thống trả lời tự động.

Một webhook trông như thế nào?

Webhook là một yêu cầu HTTP POST bình thường, thân là JSON. Ví dụ webhook opcaios.org gửi đi khi có người điền form:

{
  "id": "evt_3f9a1c2b7d8e4f60",
  "event": "submission.created",
  "createdAt": "2026-10-22T08:15:00.000Z",
  "data": {
    "form": "lien-he",
    "fields": { "name": "Nguyễn Văn A", "phone": "09…", "message": "Tôi cần tư vấn" }
  }
}

(Dữ liệu minh hoạ.)

Ba phần nên có trong mọi webhook: mã sự kiện (id) để chống xử lý trùng, loại sự kiện (event) để biết cần làm gì, và dữ liệu (data).

Ví dụ thật 1: nhận webhook thanh toán từ SePay

Khi khách chuyển khoản mua khoá học trên opcaios.org, SePay (dịch vụ theo dõi giao dịch ngân hàng) gửi webhook tới website. Website làm bốn việc:

  1. Kiểm tra khoá: yêu cầu phải mang đúng khoá bí mật đã cài trong SePay. Sai khoá thì từ chối — nếu không, ai cũng có thể giả một yêu cầu "đã thanh toán".
  2. Ghi lại mã giao dịch trước khi xử lý: nếu cùng một giao dịch được gửi lại (do mạng chập chờn, hoặc SePay gửi lại vì chưa nhận được phản hồi), lần sau sẽ bị bỏ qua, không mở khoá học hai lần.
  3. Khớp nội dung chuyển khoản với mã đơn, mở khoá học cho khách và báo tin cho chủ site.
  4. Trả lời 200 để SePay biết đã nhận, không gửi lại nữa.

Đây là khuôn mẫu cho mọi webhook nhận vào: xác thực → chống trùng → xử lý → trả lời nhanh.

Ví dụ thật 2: opcaios.org gửi webhook đi

Website cũng gửi webhook ra ngoài để nối với n8n, Make, Zapier hoặc hệ thống riêng. Chủ site vào trang quản trị, dán địa chỉ nhận và chọn các sự kiện muốn nghe:

Sự kiện Khi nào gửi
submission.created Có bài gửi mới từ form (liên hệ, khoá học, bản tin, bình luận)
order.created / order.paid Có đơn hàng shop mới / đơn đã thanh toán
contact.created Khách mới vào CRM
deal.won Cơ hội bán hàng chốt thành công
payment.paid Link thanh toán hoặc đợt thu dự án đã trả tiền
ticket.created Có yêu cầu hỗ trợ dự án mới

Mỗi webhook có một khoá ký riêng (dạng whsec_…, chỉ hiện một lần khi tạo). Mỗi lần gửi, website kèm hai header:

X-OPCAIOS-Timestamp: 1792656900
X-OPCAIOS-Signature: sha256=<HMAC-SHA256(khoá, "timestamp.body")>

Có nút gửi thử (sự kiện ping) để kiểm tra địa chỉ nhận trước khi dùng thật, và trang quản trị ghi lại kết quả lần gửi gần nhất (mã phản hồi, lỗi nếu có). Bên nhận phải trả lời trong 10 giây.

Kiểm tra chữ ký webhook như thế nào?

Chữ ký giúp bên nhận chắc chắn yêu cầu đến từ đúng nơi và không bị sửa giữa đường. Cách làm chung (gọi là HMAC): bên gửi và bên nhận cùng giữ một khoá bí mật; bên gửi dùng khoá đó "băm" nội dung thành chữ ký; bên nhận băm lại nội dung nhận được bằng cùng khoá và so sánh.

Ví dụ kiểm tra chữ ký webhook của opcaios.org bằng Node.js:

import crypto from "node:crypto";

function verify(rawBody, timestamp, signatureHeader, secret) {
  // Từ chối yêu cầu cũ hơn 5 phút, chống gửi lại yêu cầu bị đánh cắp
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader || "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Hai chi tiết hay bị bỏ sót:

  • Dùng thân yêu cầu gốc (chuỗi nhận được), không phải JSON đã được đọc rồi chuyển lại thành chuỗi — chỉ lệch một dấu cách là chữ ký sai.
  • So sánh bằng hàm an toàn (timingSafeEqual), không dùng ===, để kẻ tấn công không dò được chữ ký qua thời gian phản hồi.

Trong n8n, bạn làm việc này bằng node Crypto (HMAC) rồi node IF so sánh với header; hoặc dùng tuỳ chọn xác thực có sẵn của node Webhook nếu bên gửi dùng khoá tĩnh.

Nhận webhook không cần lập trình

  1. Trong n8n, Make hoặc Zapier, tạo quy trình bắt đầu bằng bước Webhook — công cụ sẽ cho bạn một địa chỉ URL.
  2. Dán địa chỉ đó vào phần cài đặt webhook của hệ thống gửi (SePay, website, CRM…), chọn sự kiện.
  3. Bấm gửi thử để công cụ nhận một mẫu dữ liệu, rồi ghép các trường vào bước tiếp theo: thêm dòng Google Sheets, gửi tin Telegram, tạo khách trong CRM.
  4. Bật quy trình. Từ giờ mỗi sự kiện sẽ tự chạy.

Những lỗi thường gặp khi dùng webhook

  • Xử lý trùng: bên gửi có thể gửi lại cùng một sự kiện. Luôn lưu mã sự kiện đã xử lý và bỏ qua lần lặp — nhất là với thanh toán.
  • Trả lời chậm: nhiều bên gửi chỉ chờ vài giây. Nhận xong thì trả 200 ngay, việc nặng (gửi email, gọi AI) để chạy sau.
  • Không xác thực: địa chỉ webhook là công khai trên Internet. Không kiểm tra khoá hoặc chữ ký thì ai cũng gửi được dữ liệu giả.
  • Địa chỉ không truy cập được: máy tính cá nhân, localhost hay mạng nội bộ không nhận được webhook từ Internet. Cần một máy chủ có địa chỉ công khai (hoặc dịch vụ trực tuyến như Make, Zapier, n8n cloud).
  • Không có ai theo dõi: webhook lỗi thường âm thầm. Ghi log mỗi lần nhận, và đặt cảnh báo khi lâu không thấy sự kiện hoặc lỗi liên tiếp.

Câu hỏi thường gặp

Webhook có phải là API không?
Webhook là một dạng dùng API theo chiều ngược lại: thay vì bạn gọi tới hệ thống kia, hệ thống kia gọi tới bạn. Phần lớn quy trình tự động hoá dùng cả hai — webhook để biết ngay khi có sự kiện, API để lấy thêm dữ liệu hoặc thực hiện hành động.

Webhook có mất phí không?
Bản thân webhook là một yêu cầu HTTP bình thường, không mất phí. Chi phí nếu có đến từ dịch vụ nhận (gói của Make, Zapier, máy chủ chạy n8n) hoặc dịch vụ gửi.

Nếu máy chủ của tôi tắt lúc webhook gửi tới thì sao?
Tuỳ bên gửi: có nơi gửi lại vài lần trong khoảng thời gian nhất định, có nơi chỉ gửi một lần. Đọc tài liệu của bên gửi, và với dữ liệu quan trọng như thanh toán, nên có thêm bước đối soát định kỳ bằng API.

Webhook có an toàn không?
An toàn khi bạn dùng HTTPS, kiểm tra khoá hoặc chữ ký ở mọi yêu cầu, từ chối yêu cầu quá cũ, và chống xử lý trùng.

Webhook là mảnh ghép thứ ba sau API và MCP: API để chủ động hỏi và ra lệnh, webhook để được báo ngay, MCP để trợ lý AI dùng cả hai bằng lời nói.

Nguồn: mã nguồn webhook của opcaios.org (gửi đi có ký HMAC, nhận từ SePay), kiểm tra ngày 22/10/2026.

Lê Quốc Nghĩa
Lê Quốc Nghĩa
Người xây dựng OPCAIOS

Để lại bình luận

Email của bạn sẽ không hiển thị công khai. Bình luận sẽ hiển thị sau khi được duyệt.