# What Is a Webhook? How It Works, Examples, Security

> A webhook is an automatic HTTP request sent when an event happens. Learn how it works, webhook vs API, payment and WhatsApp examples, and security.

**URL:** https://www.ciptadusa.com/blog/webhook-adalah  
**Type:** blog  
**Author:** PT Cipta Dua Saudara  
**Category:** Engineering  
**Published:** 2026-10-29  
**Cover:** https://www.ciptadusa.com/media/uploads/blog/2026-10/1793240507634-webhook-adalah-20261029.webp  

## Article

A webhook is an automatic HTTP request that one application sends to a URL owned by another application as soon as a specific event happens, such as a payment being settled, a WhatsApp message arriving, or new code being pushed to a repository. GitHub Docs explains that webhooks let you subscribe to events in a software system and automatically receive a delivery of data to your server when those events occur, as opposed to polling an API, which means calling it repeatedly to check whether new data is available ([source](https://docs.github.com/en/webhooks/about-webhooks)).

Meta's WhatsApp Business Platform documentation uses a similar definition: a webhook is an HTTP request with a JSON payload that Meta's servers send to a server of your choice to notify you about incoming messages, outgoing message statuses, and other important changes ([source](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks)). This article covers what a webhook is, how it works, how it differs from an API, examples from payment gateways, WhatsApp, Telegram, GitHub, and n8n, how to secure a webhook endpoint, and a checklist before using webhooks in business systems.

## What Is a Webhook?

Microsoft Learn describes webhooks as a pattern rather than a specific product. Implementations vary from service to service, but the idea is the same: a webhook can be seen as a simple publish/subscribe model in which a user subscribes to events happening elsewhere, and event notifications are sent as HTTP POST requests containing information about the event ([source](https://learn.microsoft.com/en-us/aspnet/webhooks/)).

A simple analogy (a CDS simplification): polling an API is like calling a courier every 10 minutes to ask whether your parcel has arrived. A webhook is like leaving your address and phone number so the courier calls you the moment the parcel arrives. The address is the webhook URL, and the courier's message is the payload.

### Key Webhook Terms

| Term | Meaning |
| --- | --- |
| Event | A change in the sending system that triggers the webhook, such as a successful payment or a new message |
| Webhook URL / endpoint | The HTTPS address on the receiving server that is registered to receive deliveries |
| Payload | The body of the delivery (Meta and Midtrans use JSON) describing what happened |
| Secret / signature | A secret key and digital signature that prove the delivery really came from the legitimate sender |
| Retry | An automatic redelivery by the sender when the receiver does not reply with a success status |
| Callback | Another name used by some providers; Xendit, for example, uses an x-callback-token header for its webhooks |

## How Does a Webhook Work?

According to Microsoft Learn, a webhook flow has three parts: the sender exposes events that clients can subscribe to, the receiver registers a webhook, and when an event occurs the sender finds matching registrations and sends an HTTP POST request. A registration consists of the target URL, a set of event filters, a secret key used to sign the request, and optional additional data ([source](https://learn.microsoft.com/en-us/aspnet/webhooks/)).

In practice, the sequence looks like this:

1. **Register a URL.** Your team creates an endpoint, for example `https://example.com/webhooks/payments`, and enters it in the provider's dashboard or API.
2. **Choose events.** GitHub recommends subscribing only to the events you need to reduce the work your server has to do ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks)).
3. **An event happens.** A customer pays, a message arrives, or an order status changes.
4. **The sender sends a POST.** The body holds a JSON payload, and the headers carry information such as the event type, a delivery ID, and a signature.
5. **The receiver replies with 2xx.** A success response confirms receipt. GitHub asks servers to respond with a 2XX status within 10 seconds; if it takes longer, GitHub terminates the connection and considers the delivery a failure ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks)).
6. **Process in the background.** To respond quickly, GitHub suggests putting payloads on a queue and processing them asynchronously ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks)).

### Example Webhook Payload

Here is an excerpt of a WhatsApp webhook payload from Meta's documentation, sent when a customer messages a business number (shortened):

```json
{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "changes": [
        {
          "field": "messages",
          "value": {
            "messages": [
              {
                "from": "16505551234",
                "type": "text",
                "text": { "body": "Does it come in another color?" }
              }
            ]
          }
        }
      ]
    }
  ]
}
```

Source: [WhatsApp webhooks documentation](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks). Payload structures differ between providers, so the receiver has to read each provider's documentation before mapping fields to a database.

## Webhook vs API: What Is the Difference?

Webhooks and APIs are not mutually exclusive. A webhook still runs over HTTP, and the receiver is essentially an API endpoint you own. The difference is who starts the communication. The general concept of an API is covered in [What Is an API?](/en/blog/api-adalah).

| Aspect | API (request-response / polling) | Webhook |
| --- | --- | --- |
| Who starts | Your application sends a request | The provider sends a POST to your URL |
| When data arrives | When you call | When the event happens |
| Load | Many calls can come back empty when there is no new data | Deliveries only happen when there is an event |
| Good for | Fetching data on demand, creating or updating data | Payment notifications, incoming messages, status changes |
| Main risk | Rate limits | Duplicate deliveries, out-of-order events, forged deliveries |

GitHub lists three advantages of webhooks over polling: they require less effort and fewer resources, they scale better because you do not have to call the API for every resource until you hit your rate limit, and they allow near real-time updates. On the other hand, if you only need information once or intermittently, or from a small set of resources, calling the API when needed is enough ([source](https://docs.github.com/en/webhooks/about-webhooks)).

In practice, the two are used together. Midtrans, for example, sends HTTP POST notifications when a transaction status changes, but also recommends calling its GET Status API when a notification is delayed or arrives out of order ([source](https://docs.midtrans.com/docs/https-notification-webhooks)). Broader integration patterns, including ETL and middleware, are covered in [What Is System Integration?](/en/blog/integrasi-sistem-adalah) and [What Is Middleware?](/en/blog/middleware-adalah).

## Webhook Examples

### Payment Gateway Webhooks

Midtrans sends HTTP(S) POST notifications to your server when a customer completes a payment or when a transaction status changes, and the target URL is set through the Payment Notification URL in the dashboard ([source](https://docs.midtrans.com/docs/https-notification-webhooks)). To confirm a successful transaction, Midtrans asks you to check three fields: status_code should be 200, fraud_status should be accept if the field exists, and transaction_status should be settlement or capture ([source](https://docs.midtrans.com/docs/https-notification-webhooks)).

Midtrans also stresses that frontend callback data, such as the Snap.js JavaScript callback, can be modified by the user and should be verified through its API ([source](https://docs.midtrans.com/docs/https-notification-webhooks)). In other words, the paid status in your system should be decided by a webhook verified on the backend, not by a "thank you" page in the browser.

Xendit explains why payments need webhooks: many payment methods require asynchronous end-user authentication, and local payment methods can take hours or days to process ([source](https://docs.xendit.co/docs/handling-webhooks)).

### WhatsApp Webhooks

The WhatsApp Business Platform uses webhooks to report incoming messages, outgoing message statuses, call events, account status changes, and template quality score changes ([source](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks)). During setup, Meta sends a GET verification request with hub.mode, hub.challenge, and hub.verify_token. Your endpoint must check that the verify token matches the one you set in the App Dashboard and respond with the hub.challenge value ([source](https://developers.facebook.com/docs/graph-api/webhooks/getting-started)).

These webhooks are the foundation for chatbots, customer service inboxes, and WhatsApp CRMs.

### Telegram Webhooks

A Telegram bot has two mutually exclusive ways of receiving updates: getUpdates (polling) or setWebhook. While a webhook is set, the bot cannot receive updates through getUpdates. The supported webhook ports are 443, 80, 88, and 8443, and the secret_token parameter makes every delivery include an X-Telegram-Bot-Api-Secret-Token header ([source](https://core.telegram.org/bots/api#setwebhook)).

### GitHub Webhooks for CI/CD

GitHub's examples include triggering CI pipelines on an external server when code is pushed, sending notifications to Slack or Discord, updating an issue tracker such as Jira, deploying to a production server, and logging events for audit purposes ([source](https://docs.github.com/en/webhooks/about-webhooks)). Automated release flows like these are part of the practices discussed in [What Is DevOps?](/en/blog/devops-adalah).

### Webhooks in n8n

In n8n, the Webhook node triggers a workflow and has two URLs: a test URL for trying things out and viewing data directly in the editor, and a production URL that becomes active after the workflow is published. The maximum payload size is 16 MB, and the endpoint can be protected with Basic auth, Header auth, or JWT auth ([source](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/)).

### Example Flow at a Distribution Company (Illustration)

The following is an illustration, not a client case study:

1. A customer pays an invoice through a virtual account.
2. The payment gateway sends a webhook to the company's backend.
3. The backend verifies the signature, records the event ID, replies 200, and puts a job on a queue.
4. A worker marks the invoice as paid in the [ERP](/en/blog/erp-adalah) and triggers a shipping order to the warehouse.
5. The [CRM](/en/blog/crm-adalah) receives the transaction history, and the customer gets a confirmation on WhatsApp.

## How to Build a Webhook Endpoint

A webhook endpoint is a regular route in your [backend](/en/blog/backend-adalah) that accepts POST requests. Below is a simple Node.js and Express example that verifies an HMAC SHA-256 signature in the style of the X-Hub-Signature-256 header (used by GitHub and Meta). It is a simplified example, not production-ready code:

```js
import express from "express";
import crypto from "node:crypto";

const app = express();

app.post("/webhook/github", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.get("X-Hub-Signature-256") || "";
  const expected = "sha256=" + crypto
    .createHmac("sha256", process.env.WEBHOOK_SECRET)
    .update(req.body)
    .digest("hex");

  const valid = signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  if (!valid) return res.status(401).send("invalid signature");

  const deliveryId = req.get("X-GitHub-Delivery");
  // store deliveryId and skip it if it was already processed
  // push the payload to a queue for background processing
  res.status(200).send("ok");
});
```

A few notes on the example:

- The signature is computed from the raw body. Stripe notes that signature verification requires the raw request body, and any manipulation of the raw body by a framework causes verification to fail ([source](https://docs.stripe.com/webhooks)).
- GitHub documents validation using a webhook secret and the X-Hub-Signature-256 header ([source](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries)).
- The X-GitHub-Delivery header can be used to protect against replay attacks because it is unique per event ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks)).
- Meta signs payloads with SHA256 using your App Secret and puts the result in the X-Hub-Signature-256 header, prefixed with sha256= ([source](https://developers.facebook.com/docs/graph-api/webhooks/getting-started)).

Other providers use different methods. Midtrans includes a signature_key computed as SHA512(order_id+status_code+gross_amount+ServerKey) ([source](https://docs.midtrans.com/docs/https-notification-webhooks)), while Xendit sends a token in the x-callback-token header ([source](https://docs.xendit.co/docs/handling-webhooks)). Telegram uses the X-Telegram-Bot-Api-Secret-Token header ([source](https://core.telegram.org/bots/api#setwebhook)).

## Webhook Security and Reliability

A webhook URL is exposed to the internet, so anyone who knows it can send forged requests. Stripe warns that without verification, an attacker could send fake events to trigger actions such as fulfilling orders, granting account access, or modifying records ([source](https://docs.stripe.com/webhooks)).

### Verify Where Deliveries Come From

- Use a random, high-entropy secret and store it securely. Do not put API keys or credentials in the webhook URL ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks)).
- Use HTTPS. Meta does not support self-signed certificates for webhook endpoints ([source](https://developers.facebook.com/docs/graph-api/webhooks/getting-started)).
- Handle webhooks on the server, not in a client application. Xendit explains that exposing webhook data and endpoints to the client side drastically increases the risk of data manipulation and man-in-the-middle attacks ([source](https://docs.xendit.co/docs/handling-webhooks)).
- If a provider publishes its IP addresses, an allow list adds another layer. GitHub provides its IP list through the GET /meta endpoint and asks you to update the list periodically ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks)).

### Duplicate Deliveries and Idempotency

Senders retry when they do not get a success response, so a receiver can get the same event more than once. Stripe recommends logging the event IDs you have processed and skipping those already logged ([source](https://docs.stripe.com/webhooks)). Midtrans recommends handling notifications idempotently, for example by using order_id as the tracking key ([source](https://docs.midtrans.com/docs/https-notification-webhooks)). Xendit provides unique IDs such as payment_id and capture_id for the same purpose ([source](https://docs.xendit.co/docs/handling-webhooks)).

### Delivery Order Is Not Guaranteed

Stripe does not guarantee that events are delivered in the order they were generated ([source](https://docs.stripe.com/webhooks)). Xendit notes that webhooks can arrive in a jumbled sequence due to network issues or latency, and recommends a message queue as a buffer ([source](https://docs.xendit.co/docs/handling-webhooks)). Midtrans describes cases where a settlement status arrives before pending, and recommends calling the GET Status API to get the latest status ([source](https://docs.midtrans.com/docs/https-notification-webhooks)).

### Timeouts and Retries at Selected Providers

| Provider | Response time limit | Retry behavior |
| --- | --- | --- |
| GitHub | Respond with 2XX within 10 seconds | Missed deliveries can be redelivered once your server is back up ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks)) |
| Midtrans | Waits up to 15 seconds, ideally answered within 5 seconds | At most 5 retries, at intervals of 2, 10, 30, 90, and 210 minutes ([source](https://docs.midtrans.com/docs/https-notification-webhooks)) |
| Stripe | Return 2xx quickly, before any complex logic | Live mode: attempts for up to three days with exponential back off ([source](https://docs.stripe.com/webhooks)) |
| Xendit | Return 2xx quickly | Up to six retries with exponential backoff ([source](https://docs.xendit.co/docs/handling-webhooks)) |
| Meta (Graph API) | Respond with 200 OK | Retries over 36 hours, then drops the update ([source](https://developers.facebook.com/docs/graph-api/webhooks/getting-started)) |

Midtrans also retries differently depending on your status code: 2XX is not retried, 500 is retried once, 503 four times, 400/404 twice, and 301/302/303 are not retried ([source](https://docs.midtrans.com/docs/https-notification-webhooks)). The response code is not a formality.

### Tolerant Parsing for New Fields

Midtrans asks receivers to parse JSON non-strictly so that fields added in the future do not make the parser throw errors ([source](https://docs.midtrans.com/docs/https-notification-webhooks)). GitHub likewise asks applications to check the event type and action before processing a payload, because new event types keep being added ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks)).

## Checklist Before Using Webhooks in Business Systems

This checklist is internal CDS guidance:

- List the events you actually need, along with the business action for each event.
- Decide which system is the source of truth for each piece of data, for example payment status in the payment gateway and stock status in the ERP.
- Set up an HTTPS endpoint, verify signatures or tokens, and store secrets securely.
- Reply with 2xx as soon as possible, then process the payload from a queue.
- Record event IDs to prevent double processing.
- Prepare reconciliation through the API to handle late, missing, or out-of-order deliveries.
- Keep delivery logs and set up alerts when the endpoint fails repeatedly.
- Test failure scenarios before go-live: wrong signature, duplicate delivery, server downtime, and payloads with new fields. Testing with users is covered in [What Is UAT?](/en/blog/uat-adalah).
- Budget for maintenance because providers can change payload formats. See [app maintenance costs](/en/blog/biaya-maintenance-aplikasi).

## Webhooks in CDS Projects

Through its [custom software development service](/en/services/software), CDS builds web apps, mobile apps, internal dashboards, and API integrations, with REST APIs and webhooks as part of the stack. For companies that already run many applications, the [IT consulting service](/en/services/consulting) covers dependency audits across systems and target architecture design, including integration and security.

CDS also develops [Zetta CRM](/en/incubating/zetta-crm), an incubating product that is a Go-based MCP server for AI agents, with Email, WhatsApp, and Threads outbound through one backend and a POST /mcp endpoint gated by an API key.

## Webhook FAQ

### What is a webhook in simple terms?

A webhook is a way for one application to notify another automatically when something happens, by sending data to a URL that was registered in advance. The receiver does not have to keep asking.

### What is a webhook URL?

A webhook URL is the endpoint address on the receiving server, for example `https://example.com/webhooks/payments`, registered in the provider's dashboard. The provider sends a POST request to this address every time a selected event occurs.

### What is the difference between a webhook and an API?

With an API, your application starts the request. With a webhook, the provider sends data to your URL when an event happens ([source](https://docs.github.com/en/webhooks/about-webhooks)). Business integrations can use both: webhooks for notifications, APIs for fetching details or rechecking status.

### Are webhooks secure?

Webhooks are secure when the endpoint uses HTTPS, verifies the provider's signature or token, keeps credentials out of the URL, and processes deliveries idempotently ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks), [source](https://docs.stripe.com/webhooks)).

### What happens if the receiving server is down?

The provider retries according to its own policy. Stripe attempts delivery for up to three days in live mode ([source](https://docs.stripe.com/webhooks)), Midtrans retries at most five times ([source](https://docs.midtrans.com/docs/https-notification-webhooks)), and GitHub recommends redelivering missed deliveries once your server is back up ([source](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks)). Your system still needs reconciliation through the API.

### Can webhooks be used without coding?

Yes, for simple flows. The n8n Webhook node provides a URL that can trigger a workflow ([source](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/)). For flows involving money, stock, or customer data, verification, idempotency, and logging still need to be designed.

## Need Webhook Integration for Your Business Systems?

If your payment gateway, WhatsApp, online store, CRM, or ERP are not connected yet, the CDS team can help design the event flow, build verified webhook endpoints, and set up reconciliation through APIs. Start with [custom software development](/en/services/software), discuss the architecture through [IT consulting](/en/services/consulting), or browse [CDS works](/en/works) first.


---

*Markdown version of https://www.ciptadusa.com/blog/webhook-adalah — generated for AI agents and LLM crawlers.*
