Guides

WhatsApp Webhooks: Verification, Signatures, and Reliable Processing

What Are Webhooks in WhatsApp Operations and Why Do They Matter?

Quick answer

WhatsApp webhook operations must distinguish Meta-to-Wats, Wats-to-customer systems, and external-system-to-Wats flows. Each direction needs source verification on the raw body, durable identifiers, deduplication, fast acknowledgement, asynchronous processing, safe recovery, monitoring, and coordinated secret rotation.

Key takeaways

  • Define the webhook direction and security contract first; Meta and Wats use different headers and secrets.
  • Verify HMAC against the raw request bytes before parsing JSON, using a constant-time comparison.
  • Return 2xx after verified durable acceptance, then move slow work to a queue or worker.
  • Expect duplicates, delay, and out-of-order delivery; make processing idempotent and avoid absolute real-time promises.
  • Rotate secrets with a short overlap and monitor failed, duplicate, and aging events.

To operate WhatsApp webhooks safely, distinguish three directions: Meta to Wats, Wats to your systems, and an external system to Wats. Each has a different secret, headers, and permission model. Verify signatures on the raw body, persist a stable event ID, deduplicate, return 2xx quickly, and perform downstream work asynchronously with recovery, monitoring, and secret rotation.

A webhook is an event notification, not proof that a business operation completed immediately. Requests can be delayed, duplicated, or delivered after a newer event, and a receiver may be temporarily unavailable. Reliability comes from the receiving contract, durable state, queue, and recovery policy—not simply from exposing a public endpoint.

Separate the event directions before designing them

“WhatsApp webhook” can refer to materially different contracts:

Direction

Sender

Receiver

Primary trust mechanism

Example

Meta → Wats

Meta's WhatsApp Business Platform

Wats inbound endpoint

Verification token for setup, then X-Hub-Signature-256 with the Meta app secret

Inbound message or message-status update

Wats → customer system

Wats

CRM, ERP, or middleware

Per-webhook secret and X-Wats-Signature

message.inbound or conversation.assigned

External system → Wats

CRM, ERP, or integration service

A Wats API or designated inbound endpoint

API token scoped to capabilities and channels, plus an idempotency contract

Eligible send request or context update

Do not use a Meta app secret to sign a Wats outgoing webhook, and never place an API token in the payload. A secret authenticates the sender; a token authorizes an API caller. They need separate ownership and lifecycle management.

If the number and Meta assets are not connected yet, start with the WhatsApp Business and Meta integration guide before implementing event consumers.

Meta to Wats: verification before event delivery

Meta's official Cloud API webhooks documentation covers event subscription and delivery. Endpoint setup normally begins with a verification GET request; event deliveries then use POST.

1. GET verification handshake

The request includes:

Parameter

Purpose

hub.mode

Must match the expected subscription mode

hub.verify_token

A shared value chosen by the receiver and compared securely

hub.challenge

Returned unchanged when verification succeeds

When the mode and token match, the endpoint returns hub.challenge with a successful response. The verification token is not a signature for subsequent deliveries and does not replace the app secret.

2. Event POST requests

For each payload, validate X-Hub-Signature-256 using HMAC SHA-256, the Meta app secret, and the raw request bytes. Meta's payload validation documentation describes the signing model. After verification, extract stable message, status, and channel identifiers and record the event before slow external work.

Meta                 Wats endpoint             Event store / worker
  | GET verification      |                              |
  |---------------------->| compare verify token         |
  |<----------------------| 200 + challenge              |
  |                       |                              |
  | POST event + signature|                              |
  |---------------------->| verify raw body              |
  |                       | persist + deduplicate ------>|
  |<----------------------| 2xx after safe acceptance    |
  |                       |                process async |

Here, 2xx means safely accepted, not that every downstream API call has finished. Waiting on a slow CRM before acknowledging Meta increases timeout, redelivery, and duplicate risk.

Wats to CRM or ERP

Wats can emit outgoing events such as message.inbound, message.outbound, conversation.assigned, conversation.escalated, and campaign.completed, filtered by event and channel. Requests include context headers such as:

X-Wats-Event
X-Wats-Webhook-Id
X-Wats-Company-Id
X-Wats-Timestamp
X-Wats-Signature: sha256=<hex-hmac-of-raw-body>

The receiver computes HMAC with the secret configured for that Wats webhook—not the Meta secret. It then combines the webhook or event identifiers and event type into a deduplication key, persists the event, and returns 2xx before performing expensive updates.

Wats event → event/channel filter → sign raw payload → HTTPS POST
                                                     ↓
CRM receiver ← 2xx ← verify → deduplicate → persist → queue
                                                     ↓
                                             update CRM/ERP async

Use the WhatsApp CRM and ERP integration guide to establish source-of-truth and identity rules before selecting events.

External system to Wats

When ERP or CRM needs to initiate an action in Wats, the appropriate contract is generally an API call or a purpose-built inbound workflow—not an unstructured webhook bounce. Give the caller a token with only the required scopes and channels, plus expiry and revocation. Carry an idempotency key or external event ID so a retry cannot create two messages or actions.

For example, an ERP emits shipment.updated to an integration service. The service verifies and stores it, then a policy gateway decides whether it is internal context only or eligible for a WhatsApp send. If eligible, it calls Wats using the same operation identifier. Do not let every back-office system push arbitrary customer-facing text directly to the channel.

A WhatsApp automation workflow can orchestrate this path, but authentication, deduplication, and the policy gate should remain explicit controls outside any prompt or free-form text.

A safe, minimal payload example

The following is an illustrative normalized event inside an integration layer, not a claim that every provider uses these exact field names:

{
  "event": "message.inbound",
  "eventId": "evt_demo_01",
  "occurredAt": "2026-05-31T06:05:12Z",
  "companyId": "cmp_demo",
  "channelId": "chn_demo",
  "data": {
    "messageId": "wamid.demo_123",
    "conversationId": "conv_demo_45",
    "direction": "inbound",
    "contentType": "text"
  }
}

Never include an app secret, access token, or customer data the consumer does not need. If CRM genuinely requires message text, apply data minimization, retention rules, and log redaction.

Correct raw-body HMAC validation

This Node.js example validates a header formatted as sha256=<hex>. Pass rawBody exactly as received before JSON parsing, and retrieve the secret from a secret manager or protected environment variable:

import crypto from "node:crypto";

export function validSignature(rawBody, signatureHeader, secret) {
  if (!signatureHeader?.startsWith("sha256=")) return false;

  const received = Buffer.from(signatureHeader.slice(7), "hex");
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest();

  return received.length === expected.length &&
    crypto.timingSafeEqual(received, expected);
}

Use the Meta app secret with X-Hub-Signature-256 for Meta deliveries, and the configured webhook secret with X-Wats-Signature for Wats deliveries. Reject missing headers, malformed hex, or a mismatch. Log a non-sensitive reason without printing the secret, full signature, or personal payload.

X-Wats-Timestamp also supports a maximum-request-age check to reduce replay risk. Allow a reasonable clock-skew window and keep deduplication as a separate control; a timestamp is not an idempotency key.

An event lifecycle that tolerates failure

Use explicit states instead of completing every dependency inside the request:

received → verified → persisted → queued → processing → processed
                                      └────→ failed → retry / review
duplicate → acknowledge without repeating the business action
  1. Received: retain the raw body and only necessary headers.

  2. Verified: validate signature, request age, and the expected contract.

  3. Persisted: store source, stable ID, hash, and initial state.

  4. Deduplicated: atomically reserve a unique key before changing business data.

  5. Queued: acknowledge with 2xx and hand the job to a worker.

  6. Processed: record resulting IDs, such as the CRM record or WhatsApp message.

  7. Failed: classify transient versus permanent failure, attempts, and next action.

Use exponential backoff with jitter for transient failure, a finite attempt limit, and then a dead-letter queue or human review. Do not endlessly retry permanent errors such as invalid payloads or missing permission before correcting their cause.

Wats has a recovery path for failed incoming Meta events that were recorded for processing. For Wats outgoing webhooks, do not assume a retry schedule, ordering, or exactly-once behavior unless the contract for the deployed version documents it. Test delivery behavior, keep the receiver idempotent, and monitor for gaps regardless.

Deduplication and out-of-order handling

A useful deduplication key combines a stable source identifier with event type, for example:

meta + message_id + status_type
wats + webhook_id + event_id
erp + source_event_id + requested_action

Reserve the key with a unique constraint or atomic transaction. A separate “check then insert” can race under concurrent delivery. Retain the completed outcome so a duplicate can receive 2xx without repeating the effect.

Out-of-order events require domain rules. If read has already been recorded and an older state arrives, do not move the message backwards. If an order update has a lower version than stored state, retain it for audit and ignore its business effect. Time alone may be insufficient; use a source sequence or version when available.

Secret rotation and monitoring

To rotate without downtime, add the new secret to the receiver, accept old and new for a short window, update the sender, observe any remaining old-secret traffic, and then revoke the old secret. Never leave the overlap open indefinitely. Meta app-secret rotation may require accepting active secrets during transition; Wats outgoing rotation requires coordinating the webhook configuration and receiver.

Monitor operational signals that do not expose customer data:

  • Accepted events and signature rejections.

  • Duplicate rate and failure reasons by endpoint.

  • Age of the oldest queued and failed event.

  • Attempt count and end-to-end processing delay.

  • Sequence gaps or count differences between source and receiver.

Avoid promising “guaranteed real time.” Event-driven or near-real-time processing is more accurate because networks, queues, and retries introduce variance. Design the interface to tolerate “updating” state and reconcile business-critical records.

How Wats applies these contracts

On the Meta inbound path, Wats validates the GET handshake and POST signature, records and deduplicates events, and tracks processing, failure, and recovery. On the outgoing path, it supports a URL, secret, event and channel filters, endpoint testing, and Wats signature headers over the raw body.

For calls from external systems, Wats API tokens support capability scopes, channel restrictions, expiry, and revocation. If an AI agent participates later in the flow, never give it the secret or authority to accept the webhook; verification and persistence are infrastructure controls that happen first. The rules, AI steps, and AI agents comparison shows where deterministic boundaries belong.

Design for receiving more than once

A reliable webhook is a security contract, state record, and recovery path—not one successful POST in a test client. Separate directions and secrets, validate raw bytes, reserve the deduplication key, acknowledge after safe acceptance, and execute downstream work outside the request. Test duplication, delay, out-of-order arrival, dependency outages, and secret rotation; that is what turns an event endpoint into an operable integration.

Frequently asked questions

Is a webhook the same as an API?

No. An API is usually called when a system requests data or an action, while a webhook is pushed by a source when an event occurs. Integrations often use both: a webhook starts the flow and an API retrieves or changes data.

Does a 200 response mean the business operation finished?

Not necessarily. It should normally mean that the receiver verified and durably accepted the event. A CRM or ERP update can complete later in an asynchronous worker.

Can the receiver parse JSON before checking the signature?

Retain the raw body and validate HMAC first. Re-serializing JSON can change spacing or field order, producing a different digest, and processing untrusted content before verification broadens risk.

What should happen when the same event arrives twice?

Create a deduplication key from the source's event or message ID plus event type. If that key is already complete, acknowledge it without repeating the business effect.

Do webhooks guarantee event order?

Do not rely on order unless the provider contract explicitly promises it. Use event time, version, and stored state, and ignore an older transition when it arrives after a newer one according to domain rules.

Try Wats free

Start free with a 30-day trial and run WhatsApp like a pro.

Get started