Blog
Công nghệCRM

Webhook là gì: cách Zalo, Facebook và biểu mẫu báo tin cho CRM, kèm chữ ký, thử lại và chống trùng

Click Star Team21 tháng 10, 202612 phút đọcCập nhật 24 tháng 10, 2026
Webhook là gì: cách Zalo, Facebook và biểu mẫu báo tin cho CRM, kèm chữ ký, thử lại và chống trùng
TÓM TẮT

Giải thích webhook là gì, khác gì gọi API chủ động, cách kiểm chữ ký, trả 2xx nhanh, thử lại, chống trùng và đối soát, dựa trên tài liệu Meta, Zalo, Stripe, GitHub.

Khi khách nhắn Zalo, điền biểu mẫu quảng cáo Facebook hay thanh toán xong, CRM cần biết ngay mà không ai phải chép tay. Cơ chế phổ biến để các hệ thống báo tin cho nhau là webhook, và phần lớn lỗi mất hoặc trùng khách tiềm năng đến từ cách nhận, hiếm khi từ phía nền tảng gửi.

Bài này giải thích webhook là gì, cách kiểm chữ ký, trả 2xx nhanh rồi xử lý sau, thử lại, chống trùng, thứ tự sự kiện và cách theo dõi. Nguồn chính là tài liệu của Meta, Zalo for Developers, Stripe, GitHub, Shopify, Next.js và RFC 9110, đối chiếu đến ngày 21/10/2026.

Click Star đã có bài riêng về API và bài về hợp nhất dữ liệu khách hàng từ biểu mẫu, Zalo, Facebook và cuộc gọi. Bài này đi vào đoạn nằm giữa: sự kiện từ nền tảng vào hệ thống của doanh nghiệp thế nào để an toàn, đủ và không trùng.

Điểm chính

  • Webhook là cách nền tảng chủ động gửi HTTP POST kèm JSON tới địa chỉ của doanh nghiệp khi có sự kiện. Meta nói cách này giúp khỏi phải truy vấn Graph API liên tục và tránh chạm giới hạn tần suất.
  • Webhook không thay hẳn việc gọi API. Shopify viết rằng việc gửi webhook không phải lúc nào cũng được bảo đảm và khuyên chạy tác vụ đối soát định kỳ.
  • Phải kiểm chữ ký trên thân yêu cầu thô. Meta và GitHub dùng HMAC-SHA256 trong X-Hub-Signature-256, Stripe thêm dấu thời gian chống phát lại, còn công thức của Zalo có dạng riêng.
  • Thời gian chờ rất ngắn: Zalo yêu cầu phản hồi 200 trong tối đa 2 giây, Messenger nêu 5 giây hoặc ít hơn, GitHub nêu 10 giây. Cách làm chuẩn là trả 2xx trước rồi xử lý nền qua hàng đợi.
  • Thử lại làm sự kiện đến trùng và thứ tự không được bảo đảm. Cần khóa chống trùng có ràng buộc duy nhất trong cơ sở dữ liệu.

So sánh webhook và gọi API chủ động

Webhook là gì và khác gì việc gọi API chủ động

Webhook là một yêu cầu HTTP mà hệ thống này tự gửi tới địa chỉ của hệ thống kia khi có sự kiện. Theo GitHub (đọc ngày 21/10/2026), webhook là cách để thông báo được chuyển tới một máy chủ bên ngoài mỗi khi có sự kiện nhất định xảy ra.

Gọi API chủ động theo chu kỳ (polling) thì ngược lại: doanh nghiệp hỏi "có gì mới không" mỗi phút hoặc mỗi giờ. Cách này đơn giản, nhưng độ trễ bằng chu kỳ hỏi và tốn lượt gọi cả khi không có gì mới.

2 cách này chia việc, không thay nhau. Webhook trả lời "vừa có gì xảy ra", còn API trả lời "trạng thái đầy đủ hiện giờ là gì".

Với biểu mẫu khách hàng tiềm năng trên Facebook, tài liệu Meta mô tả 2 đường: đăng ký trường leadgen, và đọc hàng loạt bằng GET tới mã biểu mẫu. Tài liệu ghi thông báo thời gian thực có thể trễ tới vài phút, nên đừng hứa "phản hồi trong vài giây" khi chỉ dựa vào webhook.

Một yêu cầu webhook trông thế nào

Các nền tảng giống nhau về hình thức: HTTP POST, thân JSON, vài tiêu đề mô tả sự kiện và chữ ký. Tên trường và cách ký thì khác nhau.

  • Meta: thân có object và mảng entry (id, time, changes hoặc messaging). Ở Messenger, sender.id là mã người dùng theo Trang (PSID), message.mid là mã tin nhắn.
  • Zalo: sự kiện tin nhắn có app_id, sender.id, event_name (ví dụ user_send_text), message.msg_id, timestamp và tiêu đề X-ZEvent-Signature.
  • GitHub: tiêu đề X-GitHub-Event, X-GitHub-Delivery (mã GUID của lần gửi) và X-Hub-Signature-256. Tải trọng giới hạn 25 MB.
  • Stripe: thân JSON và tiêu đề Stripe-Signature. Kiểu "thin" chỉ báo có sự kiện để bạn lấy đối tượng bằng API, kiểu "snapshot" chứa bản chụp đối tượng.

Nhiều thông báo chỉ là "chuông cửa", không phải "gói hàng". Thông báo leadgen của Meta mang leadgen_id, page_id, form_id, ad_id và created_time; tên và số điện thoại khách phải lấy bằng 1 lần gọi Graph API, cần quyền leads_retrieval.

Hành trình một sự kiện từ nền tảng đến CRM

Hành trình một sự kiện webhook từ nền tảng đến CRM qua 6 bước

Đây là khung tham khảo của Click Star, không phải mô tả của một nền tảng cụ thể. Chỉ 3 bước đầu nằm trong thời gian chờ ngắn của nền tảng.

  1. Sự kiện xảy ra (khách nhắn Zalo, gửi biểu mẫu, thanh toán) và nền tảng gửi HTTP POST.
  2. Cổng nhận kiểm chữ ký bằng thân thô, loại yêu cầu giả hoặc quá cũ.
  3. Cổng nhận ghi nguyên văn sự kiện vào bảng sự kiện thô rồi trả 2xx ngay.
  4. Tiến trình nền lấy sự kiện chưa xử lý và khử trùng bằng khóa sự kiện.
  5. Chuẩn hóa dữ liệu và, nếu thông báo mỏng, gọi API lấy dữ liệu đầy đủ.
  6. Ghi vào CRM hoặc CDP, ghép với hồ sơ đã có và lưu kết quả để theo dõi.

Bước 3 là điểm then chốt: nếu máy chủ chết sau khi trả 2xx mà chưa lưu, sự kiện mất vì nền tảng đã coi là xong. Hãy lưu trước, trả lời sau.

Xác thực: chữ ký và chống phát lại

Địa chỉ webhook là địa chỉ công khai, ai biết cũng gửi được. Stripe viết rõ: không xác minh thì kẻ tấn công có thể gửi sự kiện giả để giao đơn hay sửa bản ghi.

Chữ ký giải quyết việc này: 2 bên dùng chung 1 khóa bí mật, bên gửi tính mã HMAC (RFC 2104, mã băm có khóa) trên nội dung rồi gửi kèm, bên nhận tính lại và so sánh.

Meta. Tiêu đề X-Hub-Signature-256 dạng sha256=..., tính bằng HMAC-SHA256 với App Secret. Tài liệu Messenger lưu ý chữ ký sinh từ bản thoát Unicode của tải trọng, hex viết thường; băm bản đã giải mã sẽ ra chữ ký khác.

GitHub. Cũng X-Hub-Signature-256. Tài liệu khuyên so sánh bằng hàm thời gian không đổi như crypto.timingSafeEqual, tránh toán tử == vì có thể bị tấn công đo thời gian.

Stripe. Tiêu đề Stripe-Signature chứa t= (dấu thời gian) và v1= (chữ ký). Thư viện chính thức mặc định dung sai 5 phút để chống phát lại; đặt dung sai 0 sẽ tắt kiểm tra độ mới.

Zalo. Tài liệu ghi X-ZEvent-Signature với công thức mac = sha256(appId + data + timeStamp + OAsecretKey), data là chuỗi JSON của thân yêu cầu. Đây là phép băm nối chuỗi, khác HMAC của Meta và GitHub.

Mọi nền tảng đều cần lấy thân thô trước khi bộ phân tích JSON đọc, vì Stripe nói mọi thao tác làm đổi thân thô sẽ làm hỏng xác minh. Địa chỉ nhận cũng phải là HTTPS; Meta không hỗ trợ chứng chỉ tự ký.

Trả 2xx nhanh rồi xử lý sau

Câu trả lời cho webhook không phải kết quả xử lý, chỉ là "đã nhận". RFC 9110 mô tả lớp 2xx là yêu cầu đã được nhận, hiểu và chấp nhận; mã 202 là đã chấp nhận để xử lý nhưng chưa xong.

Thời gian chờ ngắn và khác nhau (đọc ngày 21/10/2026):

  • Zalo: phản hồi mã 200 OK, tối đa 2 giây.
  • Messenger: phản hồi 200 OK trong vòng 5 giây hoặc ít hơn.
  • GitHub: phản hồi 2xx trong 10 giây.
  • Stripe: trả 2xx trước mọi logic phức tạp; chuyển hướng 3xx bị coi là thất bại nên hãy đăng ký địa chỉ đích cuối.

Stripe và GitHub cùng khuyên xử lý bằng hàng đợi; Stripe nêu lý do là đợt tăng đột biến dễ làm quá tải nếu xử lý đồng bộ.

Với website Next.js trên Vercel, hàm after (ổn định từ 15.1.0, tài liệu cập nhật 16/9/2026) lên lịch việc chạy sau khi phản hồi đã gửi, trong giới hạn thời lượng của hàm. Click Star nhận định: after hợp để ghi nhật ký, không phải hàng đợi bền; việc cần chắc chắn nên ghi vào cơ sở dữ liệu trước.

Thử lại, lũy đẳng và chống trùng

Nền tảng thử lại khi thấy lỗi, nên một sự kiện có thể đến nhiều lần. Chính sách khác nhau rõ rệt:

  • Zalo: gửi lại sự kiện không thành công (tài liệu nêu ví dụ không mở được kết nối) sau 30 giây, 5 phút, 15 phút, 30 phút và 1 giờ, kèm num_retry ở tiêu đề. Không phục hồi thì bị hủy đăng ký.
  • Meta: thử lại ngay rồi thưa dần trong 36 giờ, sau đó bỏ. Messenger cảnh báo sau 15 phút và hủy đăng ký sau 1 giờ lỗi.
  • Stripe: tối đa 3 ngày với giãn cách tăng dần ở chế độ thật. Gửi lại thủ công được tới 15 ngày (Dashboard) hoặc 30 ngày (CLI).
  • GitHub: không tự gửi lại; phải gửi lại thủ công hoặc bằng tập lệnh, dựa vào API liệt kê các lần gửi.

Vì vậy cần thiết kế lũy đẳng (idempotent): xử lý 2 lần cho kết quả như 1 lần. Meta nói máy chủ nên tự khử trùng, Stripe khuyên ghi lại mã sự kiện đã xử lý.

Khóa chống trùng nên lấy từ nền tảng: mã sự kiện của Stripe, X-GitHub-Delivery (lần gửi lại giữ giá trị gốc) của GitHub, X-Shopify-Webhook-Id của Shopify. Meta và Zalo không nêu mã sự kiện chung ở các trang Click Star đọc; với tin nhắn, message.mid và message.msg_id là ứng viên, theo suy luận của Click Star.

Cách chắc nhất là để cơ sở dữ liệu quyết định: bảng sự kiện thô có ràng buộc duy nhất trên cặp (nguồn, khóa sự kiện), chèn kèm ON CONFLICT DO NOTHING. Tài liệu PostgreSQL ghi ON CONFLICT bảo đảm kết quả nguyên tử kể cả khi nhiều yêu cầu đến đồng thời.

Thứ tự sự kiện không được bảo đảm

Stripe viết rằng không bảo đảm giao sự kiện theo thứ tự sinh ra; Shopify nói tương tự. Tài liệu Messenger ghi tin nhắn có thể không đến đúng thứ tự và khuyên dùng trường timestamp để sắp xếp.

Stripe cảnh báo: dấu thời gian created tính bằng giây nên nhiều sự kiện có thể trùng, đừng dùng nó để quyết định thứ tự. Meta ghi trường time là lúc gửi thông báo, không phải lúc thay đổi xảy ra.

Có 3 cách xử lý:

  • Sắp theo mốc thời gian của nguồn (Shopify gợi ý X-Shopify-Triggered-At hoặc updated_at trong tải trọng).
  • Khi nhận sự kiện đến sớm, gọi API lấy đối tượng mới nhất thay vì tin nội dung sự kiện (Stripe nêu cách này).
  • Chỉ ghi đè khi mốc thời gian của sự kiện mới hơn mốc đang lưu. Đây là cách làm của Click Star, tài liệu không quy định.

5 việc bắt buộc khi nhận webhook

5 việc bắt buộc khi nhận webhook

Click Star gộp lại thành 5 việc, mỗi việc có nguồn ở các mục trước. Thiếu 1 việc thì 4 việc còn lại không bù được: chữ ký tốt mà xử lý đồng bộ vẫn quá thời gian chờ.

Theo dõi, nhật ký và kiểm thử

Stripe cho xem từng lần gửi với trạng thái Delivered, Pending, Failed và mã HTTP; GitHub cho liệt kê các lần gửi qua API.

Bảng lỗi webhook thường gặp, nguyên nhân và cách xử lý

Nhật ký nên có mã sự kiện, nguồn, thời điểm nhận, kết quả kiểm chữ ký, kết quả xử lý và số lần thử. Không ghi khóa bí mật, và cân nhắc che số điện thoại, email. Nên theo dõi tỷ lệ trả 2xx, thời gian từ lúc nhận đến lúc ghi vào CRM, độ dài hàng đợi và số bản ghi lệch khi đối soát (đề xuất của Click Star).

Về kiểm thử, Meta cho biết ứng dụng ở chế độ phát triển chỉ nhận thông báo thử, còn Stripe có lệnh stripe trigger và stripe listen. Hãy thử cả đường lỗi: chữ ký sai, gửi trùng, đảo thứ tự.

Ý nghĩa với doanh nghiệp Việt Nam

Tài liệu Zalo có điểm dễ bỏ sót (đọc ngày 21/10/2026). Địa chỉ webhook nên là tên miền HTTPS, không dùng host:port, và Official Account phải cấp Official_Account_Access_Token cho ứng dụng.

Điểm dễ gây hiểu nhầm nhất là tùy chọn "Lọc cú pháp": khi bật, webhook chỉ nhận tin nhắn văn bản bắt đầu bằng ký tự "#". Nếu CRM thiếu tin nhắn, hãy kiểm tra tùy chọn này trước.

Đánh giá của Click Star. Webhook là phần nhỏ về mã nhưng lớn về hậu quả: cổng nhận viết vội dễ làm mất khách tiềm năng mà không có dấu hiệu báo. Phần khó nằm ở các tình huống xấu: gửi lại, đảo thứ tự và lỗi nửa chừng.

Với doanh nghiệp nhỏ, 1 bảng sự kiện thô có ràng buộc duy nhất, 1 tiến trình nền và 1 tác vụ đối soát hằng ngày thường đã đủ. Về lợi ích: Click Star có làm dịch vụ tích hợp, CRM và CDP; nhận định trên dựa vào tài liệu đã đọc, không dựa vào số đo của dự án cụ thể.

Việc nên làm: lộ trình 5 ngày

  • Ngày 1: liệt kê mọi nguồn sự kiện, ghi tiêu đề chữ ký, thời gian chờ, lịch thử lại và khóa chống trùng của từng nguồn.
  • Ngày 2: dựng cổng nhận HTTPS: lấy thân thô, kiểm chữ ký, ghi bảng sự kiện thô với ràng buộc duy nhất, trả 2xx.
  • Ngày 3: dựng tiến trình nền xử lý, có thử lại giãn cách tăng dần.
  • Ngày 4: thử các đường lỗi bằng môi trường thử.
  • Ngày 5: viết tác vụ đối soát định kỳ (Shopify gợi ý lọc theo updated_at) và cảnh báo khi lỗi tăng hoặc im lặng bất thường.

Những sai lầm thường gặp

  1. Xử lý nặng ngay trong yêu cầu rồi mới trả lời, làm quá thời gian chờ và bị thử lại.
  2. Phân tích JSON rồi mới kiểm chữ ký, nên chữ ký tính trên bản đã đổi định dạng và luôn sai.
  3. Không chống trùng, nên mỗi lần thử lại tạo thêm 1 hồ sơ khách hoặc 1 đơn.
  4. Dùng thứ tự đến hoặc dấu thời gian theo giây để quyết định sự kiện nào mới hơn.
  5. Chỉ dựa vào webhook, không đối soát, không cảnh báo, đến khi nền tảng gỡ đăng ký mới biết.

Điều chưa biết

Click Star chưa có số đo độc lập về tỷ lệ webhook lỗi hay trễ ở doanh nghiệp Việt Nam. Các thời hạn và lịch thử lại là của từng nền tảng, đọc ngày 21/10/2026, và có thể đổi.

Trang Zalo không nêu định dạng giá trị của X-ZEvent-Signature, độ lệch thời gian cho phép hay mã sự kiện chung. Trang Meta về webhook chung không nêu thời gian chờ. Click Star chưa đọc được tài liệu webhook của Zalo Notification Service. Phần lớn trang được đọc qua công cụ tóm tắt, nên công thức chữ ký cần đối chiếu trang gốc.

Chia sẻ bài viếtLinkedInFacebook

Cần tư vấn cụ thể cho doanh nghiệp?

Click Star giúp anh/chị xây dựng giải pháp phù hợp ngành nghề và quy mô. Trả lời mọi câu hỏi trong giờ làm việc.

Chat ZaloNhắn tin tư vấn ngayGọi Hotline0383 406 735