Browse guides

Webhook Endpoint Setup

How to set up a webhook endpoint for the WhatsApp Cloud API and pass the Meta verification handshake — Meta sends a GET challenge your server must echo back.

On this page

Before Meta sends you any real messages, it tests that you actually own the webhook URL you registered. This one-time test is called the verification handshake. Your server must pass it before Meta activates the webhook.

Step 1 — You need a public HTTPS URL#

Your server must be reachable from the internet. During development, use ngrok to tunnel your localhost:

Code
ngrok http 3003
→ gives you: https://xxxx.ngrok-free.app

Your webhook endpoint is that URL + /webhook: https://xxxx.ngrok-free.app/webhook

Step 2 — Register it in Meta Dashboard#

Meta Dashboard → Your App → WhatsApp → Configuration → Webhook → Edit

FieldWhat to enter
Callback URLhttps://xxxx.ngrok-free.app/webhook
Verify TokenAny secret word you choose (e.g. myrahulsecret123)

Click Verify and Save.

Step 3 — The verification handshake#

The moment you click Verify, Meta sends a GET to your URL:

Code
GET /webhook?hub.mode=subscribe
             &hub.verify_token=myrahulsecret123
             &hub.challenge=RANDOM_STRING

Meta is asking: "Do you know the secret? If yes, send back the challenge." Your server checks the token and echoes the challenge:

js
app.get('/webhook', (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.WEBHOOK_VERIFY_TOKEN) {
    res.send(challenge);                    // ← pass: echo challenge back
  } else {
    res.sendStatus(403);                    // ← fail: wrong token
  }
});

If it passes → Meta activates your webhook → real messages start flowing.

Frequently asked#

What is the verify token?

A secret word you choose and set in two places: your .env file and the Meta Dashboard webhook form. Meta sends it in the handshake GET request so your server can confirm the request is genuinely from Meta.

Why does Meta say 'verification failed'?

Either your server wasn't running when Meta sent the GET request, the verify token in your .env doesn't match what you entered in Meta Dashboard, or your URL isn't publicly reachable (e.g. ngrok isn't running).

Do I need ngrok?

During development yes — your localhost is not reachable from Meta's servers. ngrok creates a public tunnel. In production, deploy your server to a real host (Render, Railway, etc.) and use that permanent URL instead.

Does the webhook URL change if I restart ngrok?

Yes — free ngrok gives a new URL every restart. You'd need to update it in Meta Dashboard each time. Paid ngrok gives a fixed domain.

Gotchas & common mistakes#

Still stuck? Open a support ticket and our team will help.