> ## Documentation Index
> Fetch the complete documentation index at: https://docs.webhook.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Verify Meta webhooks (WhatsApp, Messenger)

> Register your Meta app secret and verify token, and webhook.co verifies x-hub-signature-256 and answers the subscription handshake.

Meta's platforms (WhatsApp, Messenger, Instagram, and other Graph webhooks) sign each POST with an HMAC-SHA256 over the raw body, sent as `X-Hub-Signature-256: sha256=<hex>`. Setup uses a separate GET handshake. Register two secrets and webhook.co covers both.

## Get the two values

* **App secret** — your app's secret from **App Dashboard → App settings → Basic**. Signs the payloads.
* **Verify token** — the arbitrary string you type into **Webhooks → Configure** in the App Dashboard. Meta echoes it back during the subscription handshake.

## Register both on your endpoint

Register the app secret as the signing secret:

<CodeGroup>
  ```sh CLI theme={null}
  printf %s "$META_APP_SECRET" | wbhk endpoints add-provider-secret <endpoint-id> \
    --provider meta
  ```

  ```sh API theme={null}
  curl https://api.webhook.co/v1/endpoints/<endpoint-id>/provider-secrets \
    -H "Authorization: Bearer $WEBHOOK_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"provider":"meta","secret":"your_app_secret"}'
  ```

  ```ts TypeScript theme={null}
  await webhook.providerSecrets.add({
    endpointId,
    provider: "meta",
    secret: process.env.META_APP_SECRET!,
  });
  ```
</CodeGroup>

Then register the verify token as a second secret with `kind: verify_token`:

```sh theme={null}
printf %s "$META_VERIFY_TOKEN" | wbhk endpoints add-provider-secret <endpoint-id> \
  --provider meta --kind verify_token
```

## The subscription handshake

When you save the callback URL in the App Dashboard, Meta sends a `hub.mode=subscribe` GET carrying `hub.challenge` and `hub.verify_token`. webhook.co echoes the challenge only if the presented verify token matches the one you registered (constant-time compared), and returns 403 otherwise — so a wrong token fails setup instead of leaking the challenge.

## Confirm

```sh theme={null}
wbhk events list <endpoint-id> --status verified
```
