What is a webhook? How to receive and send webhooks safely, with real payment examples

October 22, 2026 Le Quoc NghiaGuide
What is a webhook? How to receive and send webhooks safely, with real payment examples

A webhook is how one piece of software tells another software right when something happens: a new order comes in, a customer just transferred money, someone filled out a form on the website. Instead of asking "anything new?" every few minutes, you give the source system a URL address, and the source system sends data to that address exactly when the event happens. This article explains webhooks in everyday language, how to receive and send webhooks safely, with real examples from opcaios.org, where SePay's webhook and webhooks sent to n8n are running. First is the concept, then two examples, finally signatures and common errors.

Webhook diagram: event happens, system sends POST with signature to your address
One webhook send: event happens → send data with signature → receiver checks then returns 200. Diagram: OPCAIOS.

What is a webhook?

A webhook is an HTTP POST request that the source system sends to a URL address you've registered, each time an event happens. Let me compare two ways of waiting for a delivery to arrive:

  • Calling every 10 minutes asking "has the package arrived yet?": wastes effort, and if it arrives between calls you still find out late.
  • Leaving your phone number, the delivery person calls you when they arrive: no wasted waiting, you know right away.

The first way is calling API in a continuous asking style (polling). The second way is webhook. For example, according to SePay (2026), a webhook reports a transaction to the website the moment a customer transfers money, instead of the website asking SePay every 5 minutes (one demonstration cycle).

Calling API continuously Webhook
Who takes initiative You ask The other system reports
Speed of finding out Slow, up to one asking cycle Nearly instant
Resource waste Many asks with nothing new Only sends when event happens
You need API key A URL address that can receive requests from the Internet

Where are webhooks used?

Webhooks are used everywhere you need to know about an event right away, and there are five common groups. First is payment: SePay, a service monitoring bank transfers, or a payment gateway reports "order ABC has been paid". Next is sales: marketplaces and point-of-sale software report new orders or cancellations. Third is forms and customers: website reports someone left their information, CRM reports a new customer.

  • Programming: GitHub reports new code pushed so tests run and deployment happens.
  • Messaging: Zalo OA, Messenger and Telegram send customer messages to an auto-reply system.

For example, a small shop receiving 30 orders a day can connect order webhooks to Google Sheets via n8n, so each new order automatically adds a row to the spreadsheet without anyone typing it in manually. This example is from OPCAIOS, not real figures.

What does a webhook look like?

A webhook is a normal HTTP POST request, with a JSON body, and should contain three parts: event ID, event type and data. For example the webhook opcaios.org sends in 2026 when someone fills out a form on the website, in a format that n8n, Make and Zapier can all read:

{
  "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" }
  }
}

(Sample data.)

Three parts every webhook must have: event ID (id) to prevent duplicate processing, event type (event) to know what to do, and data (data) containing the specific content. The receiver in n8n, Make or Zapier reads these 3 parts then moves each field to the next step, usually in seconds.

Real example 1: how does a website receive payment webhooks from SePay?

Receiving payment webhooks is the process of a website automatically unlocking a course when SePay reports payment arrived. According to SePay (2026), this service monitors bank transactions, and when a customer transfers money to buy a course on opcaios.org, SePay sends a webhook to the website. The website does four things in order:

  1. Check the key: the request must carry the correct secret key set up in SePay. Wrong key gets rejected, or else anyone could fake a "payment made" request.
  2. Record the transaction ID before processing: if the same transaction gets sent again due to network hiccups, next time it gets skipped, the course doesn't unlock twice.
  3. Match the transfer content with the order ID, unlock the course for the customer and notify the site owner.
  4. Reply 200 so SePay knows it received it, no need to send again.

According to opcaios.org's webhook source code (checked 22/10/2026), this is the template for every incoming webhook: verify, prevent duplicates, process, reply fast.

Real example 2: opcaios.org sends webhooks out

My website also sends webhooks outward to connect with n8n, Make, Zapier, or custom systems. I go to the admin page, paste the receiving address, and choose which events I want to listen for:

Event When sent
submission.created New form submission (contact, course, newsletter, comment)
order.created / order.paid New shop order / order paid
contact.created New customer in CRM
deal.won Sales opportunity closed successfully
payment.paid Payment link or project billing round paid
ticket.created New support request for project

Each webhook has its own secret key (format whsec_…, shown only once when created). Each time I send, my website includes two headers:

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

There's a test send button (a ping event) to check the receiving address before using it for real, and the admin page logs the result of the most recent send (response code, errors if any). The receiver must respond within 10 seconds.

How do I check webhook signatures?

A webhook signature is a code that helps the receiver be sure the request came from the right place and wasn't changed in transit. The general approach is called HMAC: both sender and receiver keep a secret key, the sender uses the key to "hash" the content into a signature, the receiver hashes the received content again with the same key and compares.

According to opcaios.org's source code (2026), the example below checks webhook signatures in Node.js and rejects any request older than 5 minutes:

import crypto from "node:crypto";

function verify(rawBody, timestamp, signatureHeader, secret) {
  // Reject requests older than 5 minutes, prevent replay of stolen requests
  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);
}

Two details are often overlooked:

  • Use the raw request body (the string as received), not JSON that was already parsed and converted back to a string: even one space difference makes the signature wrong.
  • Compare with a safe function (timingSafeEqual), not ===, so an attacker cannot guess the signature by timing the response.

In n8n, you do this with the Crypto node (HMAC) then an IF node to compare with the header; or use the built-in authentication option on the Webhook node if the sender uses a static key.

Receive webhooks without coding

  1. In n8n, Make, or Zapier, create a workflow that starts with a Webhook step — the tool gives you a URL address.
  2. Paste that address into the webhook settings of the sending system (SePay, website, CRM…), and choose the event.
  3. Click test send so the tool receives sample data, then wire the fields into the next step: add a row to Google Sheets, send a Telegram message, create a customer in your CRM.
  4. Turn on the workflow. From now on each event runs automatically.

What are common webhook mistakes?

Common webhook mistakes fall into five types, and any of them cause events to be lost or duplicated. For example, a payment processed twice is the result of the first mistake below, and according to OPCAIOS (2026) all five should be checked before you start:

  • Duplicate handling: the sender can resend the same event. Always save the event ID you have processed and skip duplicates, especially for payments.
  • Slow response: many senders only wait a few seconds. Receive it, return 200 right away, and run heavy work like sending email or calling AI afterward.
  • No authentication: a webhook address is public on the Internet. Not checking the key or signature means anyone can send fake data.
  • Address unreachable: a personal computer or internal network cannot receive webhooks from the Internet. I need a server with a public address, or an online service like Make, Zapier, n8n cloud.
  • No one watching: webhook failures are usually silent. Log every receive, and set alerts when you haven't seen an event in a while or get errors in a row.

Read more: Collect payment for digital products via QR bank transfer (SePay) for solo workers; Automate your lead funnel.

Frequently Asked Questions

Is a webhook an API?

A webhook is a type of API used in reverse: instead of you calling another system, that system calls you. Most automation workflows use both. Webhooks help you know immediately when an event happens, while APIs help you fetch more data or perform actions. For example, SePay sends a webhook to report incoming payment, then the website calls an internal API to unlock a course and send a confirmation email to the customer. See the article What is an API if you're not familiar with the concept yet.

Do webhooks cost money?

Webhooks themselves are normal HTTP requests so they don't cost anything. If there are costs, they come from the receiving service like Make, Zapier packages or a server running n8n, or from the sending service. Therefore, before using them, check the current pricing table of each service on their official website, since prices and monthly execution limits change over time. This article doesn't mention specific prices because OPCAIOS hasn't verified the latest pricing tables of those services.

What if my server is down when a webhook is sent?

The result depends on the sender: some will resend several times within a certain timeframe, others will only send once. First, read the sender's documentation to know their resend policy. Next, for important data like payments, add a periodic reconciliation step using API to catch missed events. Finally, log every time you receive to know what your server downtime missed.

Are webhooks safe?

Webhooks are safe when you use HTTPS, check a key or signature on every request, reject requests that are too old, and prevent duplicate processing. According to the webhook source code of opcaios.org (checked on 22/10/2026), the website checks the key and prevents duplicate processing for incoming SePay webhooks, while also signing outgoing webhooks with HMAC-SHA256 plus a timestamp.

A webhook is the third piece after API and MCP: API for actively asking and giving orders, webhooks to be notified immediately, MCP for AI assistants to use both through natural language.

Source: webhook source code of opcaios.org (outgoing ones are signed with HMAC, incoming from SePay), checked on 22/10/2026.

Translated from Vietnamese with AI. Read the original.

Want to apply this in your business?

Book a free 30-minute call (Vietnam time, in English or Vietnamese).

Book a call