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

# Webhooks

> How WapNotify receives WhatsApp events — webhook verification, inbound message payloads, and signature verification.

WapNotify receives WhatsApp events (incoming messages, delivery status updates) via a webhook endpoint registered with Meta. This page explains the webhook mechanism for developers integrating or debugging.

## Webhook endpoints

| Method | Path           | Purpose                                   |
| ------ | -------------- | ----------------------------------------- |
| `GET`  | `/api/webhook` | Meta webhook verification (hub challenge) |
| `POST` | `/api/webhook` | Inbound messages and status updates       |

Both endpoints are public — no `Authorization` header is needed. Security is provided by HMAC signature verification on POST requests.

## Webhook verification (GET)

When you register your webhook URL in Meta, Meta sends a GET request to verify ownership:

```
GET /api/webhook?hub.mode=subscribe&hub.verify_token=YOUR_VERIFY_TOKEN&hub.challenge=CHALLENGE_STRING
```

WapNotify checks that `hub.verify_token` matches the `Webhook Verify Token` stored in your workspace settings. If it matches, it responds with the `hub.challenge` value and a `200` status.

If verification fails, check that the Verify Token in Meta matches exactly what you entered in **Settings → WhatsApp Setup**.

## Inbound events (POST)

Meta sends a POST request for every event — incoming messages, delivery receipts, read receipts.

### Signature verification

Every POST request includes an `x-hub-signature-256` header:

```
x-hub-signature-256: sha256=<hmac_hex>
```

WapNotify computes `HMAC-SHA256(raw_body, app_secret)` and compares it to the header value. Requests that fail signature verification are rejected with `403 Forbidden`.

The `app_secret` is the App Secret stored in your workspace WhatsApp settings (from Meta → Settings → Basic).

### Example: inbound text message

```json theme={null}
{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "WABA_ID",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "919876543210",
              "phone_number_id": "PHONE_NUMBER_ID"
            },
            "contacts": [
              {
                "profile": { "name": "Rahul Sharma" },
                "wa_id": "919876543210"
              }
            ],
            "messages": [
              {
                "from": "919876543210",
                "id": "wamid.HBgLOTE5ODc2...",
                "timestamp": "1719859200",
                "text": { "body": "Hello, I'd like to place an order." },
                "type": "text"
              }
            ]
          },
          "field": "messages"
        }
      ]
    }
  ]
}
```

### Example: delivery status update

```json theme={null}
{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "WABA_ID",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "statuses": [
              {
                "id": "wamid.HBgLOTE5ODc2...",
                "status": "delivered",
                "timestamp": "1719859260",
                "recipient_id": "919876543210"
              }
            ]
          },
          "field": "messages"
        }
      ]
    }
  ]
}
```

Status values: `sent`, `delivered`, `read`, `failed`.

## Retry behaviour

Meta retries failed webhook deliveries (non-2xx responses) with exponential backoff. WapNotify deduplicates messages using the `wa_message_id` field — receiving the same message ID twice is safe.
