Skip to content
WhatsApp Business API

WhatsApp Webhooks Explained: Receive Messages & Status Updates (Developer Guide 2026)

Webhooks are how the WhatsApp Business API tells your server about incoming messages and delivery statuses. This guide covers verification, payload structure, signature checks, retries and production best practices.

Aditya Naida

· 4 min read

  • 7-day free trial
  • No credit card
  • Setup help on WhatsApp
  • Plans from ₹999/month + GST
WhatsApp Webhooks Explained: Receive Messages & Status Updates (Developer Guide 2026)

Share

Sending messages through the WhatsApp Business API is only half the job. The other half — knowing when a customer replies, when a message is delivered or read, and when something fails — happens through webhooks. Get webhooks right and your inbox, chatbot and analytics run in real time. Get them wrong and you miss messages, double-process events or see silent failures.

This guide is for developers integrating the WhatsApp Cloud API directly or through a provider.

What is a WhatsApp webhook?

A webhook is an HTTPS endpoint on your server that Meta calls whenever something happens on your WhatsApp Business Account. Instead of polling an API to ask “any new messages?”, Meta pushes each event to you as a JSON POST request within seconds.

The main event types arrive under the messages field:

  • Incoming messages — text, images, documents, audio, location, contacts, button clicks, list selections and Flow responses.
  • Message statuses — sent, delivered, read and failed for messages you sent.

Other fields cover template status updates (approved, rejected, paused), phone number quality changes and account updates.

WhatsApp webhook lifecycle: verify, receive, validate, acknowledge, process

Step 1: Verify your endpoint

When you register a webhook URL in your Meta app, Meta sends a GET request with three query parameters: hub.mode (always subscribe), hub.verify_token (the string you chose) and hub.challenge. If the token matches, respond with the challenge value and status 200.

app.get('/webhooks/whatsapp', (req, res) => {
  const mode = req.query['hub.mode'];
  const token = req.query['hub.verify_token'];
  const challenge = req.query['hub.challenge'];
  if (mode === 'subscribe' && token === process.env.VERIFY_TOKEN) {
    return res.status(200).send(challenge);
  }
  return res.sendStatus(403);
});

Then subscribe your app to the WhatsApp Business Account and select the messages field.

Step 2: Understand the payload

Every POST follows the same envelope: object → entry[] → changes[] → value. Inside value you'll find metadata (your phone number ID), and either contacts + messages for inbound messages, or statuses for delivery updates.

{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "WABA_ID",
    "changes": [{
      "field": "messages",
      "value": {
        "messaging_product": "whatsapp",
        "metadata": { "phone_number_id": "PHONE_NUMBER_ID" },
        "contacts": [{ "profile": { "name": "Riya" }, "wa_id": "9198XXXXXX10" }],
        "messages": [{
          "from": "9198XXXXXX10",
          "id": "wamid.XXXX",
          "timestamp": "1791600000",
          "type": "text",
          "text": { "body": "Hi, is this available?" }
        }]
      }
    }]
  }]
}

A status event looks similar but carries statuses[] with the message ID, status, recipient, timestamp and — for failures — an errors array explaining why.

Step 3: Validate the signature

Anyone can POST to a public URL, so always verify that requests come from Meta. Each request includes an X-Hub-Signature-256 header: an HMAC-SHA256 hash of the raw request body, keyed with your app secret. Compute the same hash and compare using a constant-time comparison.

const crypto = require('crypto');
function isValid(rawBody, header) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.APP_SECRET)
    .update(rawBody)
    .digest('hex');
  return header && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

Important: compute the hash on the raw bytes, before any JSON parsing middleware modifies the body.

Step 4: Acknowledge quickly, process asynchronously

Return 200 OK as soon as you've validated and stored the event. If your endpoint is slow, errors or times out, Meta retries delivery with back-off, which can lead to duplicates and delays. The production pattern is:

  1. Validate signature.
  2. Push the raw event to a queue (Redis, SQS, RabbitMQ, Kafka).
  3. Respond 200.
  4. Workers consume the queue and update your database, inbox, bot or CRM.

Step 5: Handle duplicates and ordering

  • Idempotency: use the message ID (wamid) as a unique key. If you've already processed it, skip it.
  • Out-of-order statuses: a read may arrive before delivered. Only move a status forward (sent → delivered → read), never backward.
  • Failed statuses: log the error code and trigger fallbacks — for example, SMS for an undelivered OTP.

Common message types to handle

typeWhat to read
texttext.body
image / document / audio / videoMedia ID — download it via the media endpoint
interactivebutton_reply or list_reply IDs, or nfm_reply for Flows
buttonQuick-reply button tapped on a template
locationLatitude, longitude, name and address

Production checklist

  • HTTPS with a valid certificate
  • Signature validation on every request
  • Queue-based processing with retries and dead-letter handling
  • Idempotent handlers keyed on message ID
  • Monitoring and alerting for webhook error rates
  • Separate endpoints or routing for staging and production numbers

Using webhooks with Splashify Pro

If you use Splashify Pro, Meta's webhooks are handled for you: incoming messages appear in the shared inbox, statuses update in real time, and chatbots respond automatically. You can also forward events to your own systems through Splashify Pro's outgoing webhooks to sync with your CRM, ERP or data warehouse. See the API guide for an overview.

Frequently asked questions

Why am I not receiving webhook events?

Check that your app is subscribed to the WhatsApp Business Account, the messages field is selected, your endpoint returns 200 quickly and your certificate is valid.

Can I have multiple webhook URLs?

Each Meta app has one callback URL for WhatsApp. To fan out to several systems, receive events once and forward them internally.

How do I test webhooks locally?

Use a tunnelling tool to expose your local server over HTTPS, register that URL, and send test messages from a real phone.

The bottom line

Verify, validate, acknowledge fast and process asynchronously with idempotency — that's the recipe for reliable WhatsApp webhooks. Want to skip the plumbing? Start with Splashify Pro and get messages, statuses and automations working out of the box.

  • #whatsapp api webhook
  • #whatsapp cloud api webhook
  • #whatsapp message status webhook
  • #whatsapp webhook
More articles you might find useful.

Questions about Splashify Pro

Still have a question?

Three plans: Growth ₹999/month (1 team member), Advanced ₹2,999/month (5 team members) and Enterprise ₹7,999/month (15 team members). All in INR, plus GST. Quarterly billing saves 5% and yearly billing saves 10%. WhatsApp message charges are billed on top of the plan, per message you send.

Still have a question?

Put this into practice. Start your free trial.

  • 7-day free trial
  • No credit card
  • Setup help on WhatsApp
Chat on WhatsApp (opens in a new tab)