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

# Webhooks

> Webhook endpoints for receiving delivery status callbacks from external providers.

## WhatsApp Webhook

Receives delivery status callbacks from the Meta WhatsApp Cloud API.

### Verification (GET)

Meta requires webhook verification during setup. When you configure the webhook URL in the Meta Developer Dashboard, Meta sends a verification request.

```
GET /api/v1/webhooks/whatsapp?hub.mode=subscribe&hub.verify_token=YOUR_TOKEN&hub.challenge=CHALLENGE
```

**Query Parameters:**

| Parameter          | Description                                             |
| ------------------ | ------------------------------------------------------- |
| `hub.mode`         | Must be `subscribe`                                     |
| `hub.verify_token` | Must match your `WHATSAPP_WEBHOOK_VERIFY_TOKEN` env var |
| `hub.challenge`    | Challenge string to echo back                           |

**Response:** Returns the `hub.challenge` value as plain text (200) if token matches, or 403 if verification fails.

### Status Callbacks (POST)

Meta sends delivery status updates as POST requests when message statuses change.

```
POST /api/v1/webhooks/whatsapp
```

**Payload (from Meta):**

```json theme={null}
{
  "object": "whatsapp_business_account",
  "entry": [{
    "changes": [{
      "value": {
        "statuses": [{
          "id": "wamid.ABCdef123",
          "status": "delivered",
          "timestamp": "1679000000"
        }]
      }
    }]
  }]
}
```

**Status Mapping:**

| Meta Status | KaireonAI Status |
| ----------- | ---------------- |
| `sent`      | `delivered`      |
| `delivered` | `delivered`      |
| `read`      | `opened`         |
| `failed`    | `failed`         |

**Response:** Always returns 200 to acknowledge receipt.

### Signature Verification

WhatsApp webhooks are verified using **HMAC-SHA256 signature verification**. Meta signs every POST payload with your app secret and includes the signature in the `x-hub-signature-256` header.

The platform computes the expected signature using the `WHATSAPP_APP_SECRET` environment variable and compares it to the header value using `crypto.timingSafeEqual` to prevent timing attacks. Requests with missing or invalid signatures are rejected with `401`.

### Environment Variables

| Variable                        | Required | Description                                                            |
| ------------------------------- | -------- | ---------------------------------------------------------------------- |
| `WHATSAPP_WEBHOOK_VERIFY_TOKEN` | Yes      | Token for Meta webhook verification (GET requests)                     |
| `WHATSAPP_APP_SECRET`           | Yes      | Meta app secret for HMAC-SHA256 signature verification (POST requests) |

***

## Delivery Webhook

Universal delivery status webhook that auto-detects provider payload formats.

```
POST /api/v1/webhooks/delivery
```

Handles delivery status callbacks from multiple providers. The endpoint automatically detects the payload format and normalizes it into a standard event structure.

### Supported Providers

| Provider     | Detection Method                                               | Payload Format                              |
| ------------ | -------------------------------------------------------------- | ------------------------------------------- |
| **AWS SES**  | `notificationType` field or SNS `Type: "Notification"` wrapper | SNS notification with nested JSON `Message` |
| **SendGrid** | Array payload with `sg_message_id` field                       | Array of event objects                      |
| **Twilio**   | Message-SID field on the form body (see example below)         | Form-style status callback                  |
| **Standard** | `providerMessageId` + `event` fields                           | KaireonAI native format                     |

You can also pass an `X-Provider` header (`ses`, `sendgrid`, `twilio`) to explicitly hint the format.

#### Twilio status-callback form body

Twilio sends delivery status as an `application/x-www-form-urlencoded` POST. The endpoint detects the format by the presence of the message-SID field (the preferred form) or its legacy alias. See the [Twilio Message Status Values reference](https://www.twilio.com/docs/sms/api/message-resource#message-status-values) for the full list of status values. The exact wire-field names are shown in the example below:

```bash theme={null}
# Example status-callback POST that Twilio sends to your webhook URL
curl -X POST https://your-domain.kaireonai.com/api/v1/webhooks/delivery \
  -d "MessageSid=SM1234567890abcdef1234567890abcdef" \
  -d "SmsSid=SM1234567890abcdef1234567890abcdef" \
  -d "MessageStatus=delivered" \
  -d "To=%2B15005550006" \
  -d "From=%2B15005550001"
```

### Signature Verification

Delivery webhooks are verified using **HMAC-SHA256 signature verification**. Include the signature in the `X-Webhook-Signature` header:

```
X-Webhook-Signature: sha256=<hex-encoded-hmac>
```

The HMAC is computed over the raw request body using the `WEBHOOK_SIGNING_SECRET` environment variable. Requests with missing or invalid signatures are rejected with `401`.

### Normalized Events

All provider payloads are normalized to a standard event:

| Event       | Description                            |
| ----------- | -------------------------------------- |
| `delivered` | Message was delivered to the recipient |
| `bounced`   | Message bounced or was marked as spam  |
| `opened`    | Recipient opened the message           |
| `clicked`   | Recipient clicked a link               |
| `failed`    | Delivery failed                        |

### Environment Variables

| Variable                 | Required | Description                                          |
| ------------------------ | -------- | ---------------------------------------------------- |
| `WEBHOOK_SIGNING_SECRET` | Yes      | Shared secret for HMAC-SHA256 signature verification |
