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

# WhatsApp Webhooks

> Configure Antryk WhatsApp webhooks to receive real-time customer messages, delivery updates, message events, and WhatsApp activity securely in your application.

Antryk WhatsApp Webhooks allow you to receive real-time WhatsApp events directly in your application.

Configure a **Callback URL** and **Signing Secret** from your WhatsApp Service dashboard to receive incoming customer messages, message updates, delivery statuses, and other WhatsApp activity through HTTP POST requests.

With Antryk WhatsApp Webhooks, you can build:

* Automated customer support
* WhatsApp chatbots
* Real-time notifications
* Order and delivery workflows
* Customer communication systems
* Message synchronization
* Delivery tracking
* WhatsApp automation
* CRM integrations
* Custom backend workflows

***

## How WhatsApp Webhooks Work

The Antryk webhook workflow consists of four main steps:

1. Create or connect a WhatsApp Business service in Antryk.
2. Configure your application's webhook endpoint as the **Callback URL**.
3. Add a **Signing Secret** to securely authenticate webhook requests.
4. Receive and process WhatsApp events in your backend.

When WhatsApp activity occurs, Antryk sends an HTTP `POST` request to your configured Callback URL.

```text theme={null}
WhatsApp Activity
       ↓
    Antryk
       ↓
Webhook POST Request
       ↓
Your Callback URL
       ↓
Verify Signature
       ↓
Process Event
       ↓
Return HTTP 2xx Response

```

### Configure WhatsApp Webhook

To configure a webhook, first open the WhatsApp service you want to configure.

#### Setup Steps

1. Open the WhatsApp Services section in your Antryk dashboard.
2. Select the WhatsApp Business service you want to configure.
3. Open the Overview page.
4. Click the Webhook button.
5. Enter your application's Callback URL.
6. Configure a Signing Secret.
7. Review the sample payload.
8. Click Send Test Event to verify connectivity.
9. Click Save Configuration.

### WhatsApp Webhook Configuration

The WhatsApp webhook configuration drawer contains the settings required to connect your Antryk WhatsApp service to your backend application.

#### Callback URL

The Callback URL is the public API endpoint where Antryk sends WhatsApp webhook events.

For example:

`https://api.example.com/webhooks/whatsapp`

Your backend should expose this endpoint and accept HTTP POST requests.

The endpoint should be publicly reachable by Antryk and should be capable of receiving JSON request bodies.

#### Signing Secret

The Signing Secret is a private secret used to verify that webhook requests were sent by Antryk.

You should store this secret securely in your backend environment rather than hard-coding it directly into your application source code.

For example:

`WHATSAPP_WEBHOOK_SECRET=your_callback_secret`

> **Security:** Never expose your webhook signing secret in frontend code, public repositories, client-side applications, or browser-accessible configuration.

#### Sample Payload

The webhook configuration drawer provides a sample payload that will be used in sending test event to check connectivity of entered callback URL.

#### Webhook Configuration Actions

* **Cancel** — Close the webhook configuration drawer without saving changes.
* **Send Test Event** — Send a sample webhook request to your Callback URL.
* **Save Configuration** — Save the Callback URL and Signing Secret.

***

## Building Your Webhook Endpoint

The Callback URL you configure in Antryk must point to a backend route in your application.

For example, if you configure:

`https://api.example.com/webhooks/whatsapp`

your backend should have a corresponding route:

`POST /webhooks/whatsapp`

Antryk will send the WhatsApp event as a JSON request body.

Your backend should:

1. Receive the POST request.
2. Read the `X-Webhook-Signature` header.
3. Retrieve the signing secret from your environment variables.
4. Calculate the expected signature.
5. Compare the received signature with the calculated signature.
6. Reject the request if the signature is invalid.
7. Process the webhook event.
8. Return a successful HTTP 2xx response.

***

## Webhook Signature Verification

Every webhook request contains the following HTTP header:

`X-Webhook-Signature`

The header contains a SHA-256 HMAC signature generated using the Signing Secret configured for your WhatsApp service.

The signature format is:

`sha256=<signature>`

Your backend should calculate the expected signature using the raw request payload and your webhook secret.

### Signature Verification Flow

```text theme={null}
Antryk
  ↓
POST webhook request
  ↓
X-Webhook-Signature header
  ↓
Your backend
  ↓
Read webhook secret from environment
  ↓
Generate HMAC SHA-256 signature
  ↓
Compare signatures
  ↓
Valid → Process event
Invalid → Return 401

```

> **Important:** The webhook secret should be stored as an environment variable or another secure server-side secret store. Do not hard-code production secrets in your source code.

### JavaScript Signature Verification

The following example demonstrates how to verify an Antryk webhook request using Node.js and JavaScript.

```javascript theme={null}
const crypto = require("crypto");

function verifyWebhookSignature(req) {
  const signature = req.headers["x-webhook-signature"];
  const secret = process.env.WHATSAPP_WEBHOOK_SECRET;

  if (!signature || !secret) {
    return false;
  }

  const expectedSignature =
    "sha256=" +
    crypto
      .createHmac("sha256", secret)
      .update(JSON.stringify(req.body))
      .digest("hex");

  return signature === expectedSignature;
}
```

A basic Express route can then use the verification function:

```javascript theme={null}
const express = require("express");
const crypto = require("crypto");

const app = express();

app.use(express.json());

app.post("/webhooks/whatsapp", (req, res) => {
  const signature = req.headers["x-webhook-signature"];
  const secret = process.env.WHATSAPP_WEBHOOK_SECRET;

  if (!signature || !secret) {
    return res.status(401).send("Invalid signature");
  }

  const expectedSignature =
    "sha256=" +
    crypto
      .createHmac("sha256", secret)
      .update(JSON.stringify(req.body))
      .digest("hex");

  if (signature !== expectedSignature) {
    return res.status(401).send("Invalid signature");
  }

  const event = req.body;

  // Process the verified webhook event.
  console.log("WhatsApp webhook event:", event);

  return res.status(200).json({
    success: true,
  });
});

app.listen(3000, () => {
  console.log("Webhook server listening on port 3000");
});
```

#### JavaScript Environment Variable

Store the Signing Secret in your server environment:

```env theme={null}
WHATSAPP_WEBHOOK_SECRET=your_callback_secret

```

Do not commit this value to Git or expose it to frontend applications.

### Python Signature Verification

The following example demonstrates webhook signature verification using Python.

```python theme={null}
import os
import hmac
import hashlib
import json

def verify_webhook_signature(request):
    signature = request.headers.get("X-Webhook-Signature")
    secret = os.environ.get("WHATSAPP_WEBHOOK_SECRET")

    if not signature or not secret:
        return False

    payload = json.dumps(request.json, separators=(",", ":"))

    expected_signature = "sha256=" + hmac.new(
        secret.encode("utf-8"),
        payload.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(signature, expected_signature)

```

A Flask webhook route can use the verification function like this:

```python theme={null}
import os
import hmac
import hashlib
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/webhooks/whatsapp", methods=["POST"])
def whatsapp_webhook():
    signature = request.headers.get("X-Webhook-Signature")
    secret = os.environ.get("WHATSAPP_WEBHOOK_SECRET")

    if not signature or not secret:
        return "Invalid signature", 401

    payload = request.get_data()

    expected_signature = "sha256=" + hmac.new(
        secret.encode("utf-8"),
        payload,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature, expected_signature):
        return "Invalid signature", 401

    event = request.get_json()

    # Process the verified webhook event.
    print("WhatsApp webhook event:", event)

    return jsonify({
        "success": True
    }), 200

if __name__ == "__main__":
    app.run(port=3000)

```

#### Python Environment Variable

Store your webhook Signing Secret as an environment variable:

```env theme={null}
WHATSAPP_WEBHOOK_SECRET=your_callback_secret

```

Do not store the production Signing Secret directly in your Python source code.

***

## Webhook Response Status Codes

Your webhook endpoint should return an HTTP status code indicating whether the request was successfully received and processed.

### Successful Responses

Return a 2xx response when the webhook has been accepted.

For example:

`HTTP/1.1 200 OK`

A successful response tells Antryk that your endpoint received the webhook successfully.

### Invalid Signature

If the `X-Webhook-Signature` does not match the signature calculated using your configured secret, reject the request.

For example:

`HTTP/1.1 401 Unauthorized`

Example response:

`Invalid signature`

### Other Failed Requests

If your endpoint returns an error or cannot be reached, Antryk may retry webhook delivery.

Common failure scenarios include:

* **401** — Invalid webhook signature.
* **4xx** — Invalid or rejected request.
* **5xx** — Server-side processing error.
* **Timeout** — Your endpoint did not respond within the expected time.
* **Connection failure** — Your endpoint could not be reached.

### Recommended Webhook Response Flow

A recommended webhook handler follows this pattern:

```text theme={null}
Receive webhook request
          ↓
Read X-Webhook-Signature
          ↓
Load secret from environment
          ↓
Verify HMAC SHA-256 signature
          ↓
       Valid?
       /    \
     No      Yes
     ↓        ↓
Return 401  Process event
              ↓
            Return HTTP 200

```

Always verify the webhook signature before trusting or processing the payload.

***

## WhatsApp Webhook Events

When your account receives WhatsApp activity, Antryk forwards a clean, normalized payload to your configured Callback URL using an HTTP POST request.

All webhook requests are signed using your configured Signing Secret. Your backend should verify the signature before processing the event.

### Event Types Overview

| Event             | Triggered When                                                             |
| ----------------- | -------------------------------------------------------------------------- |
| `message`         | A customer sends a message such as text, image, video, or document         |
| `message_echo`    | Your team sends a message directly from the WhatsApp Business app          |
| `message_edited`  | Your team edits a message previously sent from the WhatsApp Business app   |
| `message_revoked` | Your team deletes a message previously sent from the WhatsApp Business app |
| `message_status`  | A message changes delivery state such as sent, delivered, read, or failed  |

### 1. `message` — Incoming Customer Message

The `message` event is fired when a customer sends a message to your WhatsApp Business number.

```json theme={null}
{
  "event": "message",
  "from": "16315551181",
  "to": "16505551111",
  "messageId": "a1b2c3d4-internal-uuid",
  "waMessageId": "wamid.HBgLMTYzMTU1NTExODEVAgARGBI4...",
  "messageType": "text",
  "body": "Hi, is this order shipped yet?",
  "mediaUrl": null,
  "timestamp": "2026-08-21T09:12:44.000Z",
  "phoneNumberId": "123456123",
  "wabaId": "987654987",
  "contact": {
    "profile": {
      "name": "John Doe"
    },
    "wa_id": "16315551181"
  }
}
```

#### Field Notes

* `from` — Customer's phone number.
* `to` — Your business WhatsApp number.
* `messageType` — Message type such as text, image, audio, video, document, or template.
* `body` — Message text or media caption.
* `mediaUrl` — URL of the resolved media file. This can temporarily be null immediately after receiving the message while media is being resolved.

### 2. `message_echo` — Message Sent From the App

The `message_echo` event is fired when someone from your team sends a message directly from the connected WhatsApp Business app rather than through the Antryk API.

This keeps your records synchronized with messages manually sent by your staff.

```json theme={null}
{
  "event": "message_echo",
  "from": "16505551111",
  "to": "16315551181",
  "messageId": "e5f6g7h8-internal-uuid",
  "waMessageId": "wamid.HBgLMTYzMTU1NTExODEVAgARGBI5...",
  "messageType": "text",
  "body": "Yep, shipped this morning!",
  "mediaUrl": null,
  "timestamp": "2026-08-21T09:14:02.000Z",
  "phoneNumberId": "123456123",
  "wabaId": "987654987",
  "contact": null
}
```

#### Field Notes

* `from` — Your business WhatsApp number because the message was sent by your team.
* `to` — The customer who received the message.
* The remaining fields follow the same structure as an incoming message.
* If the message was originally sent through the Antryk Send Message API, a duplicate `message_echo` event is not generated because messages are deduplicated using `waMessageId`.

### 3. `message_edited` — App Message Edited

The `message_edited` event is fired when your staff edits a message previously sent from the WhatsApp Business app.

```json theme={null}
{
  "event": "message_edited",
  "from": "16505551111",
  "to": "16315551181",
  "messageId": "e5f6g7h8-internal-uuid",
  "waMessageId": "wamid.HBgLMTYzMTU1NTExODEVAgARGBI5...",
  "messageType": "text",
  "body": "Yep, shipped this morning — tracking number below!",
  "mediaUrl": null,
  "timestamp": "2026-08-21T09:15:10.000Z",
  "phoneNumberId": "123456123",
  "wabaId": "987654987",
  "contact": null
}
```

#### Field Notes

* `waMessageId` refers to the original WhatsApp message. Use it to locate and update the corresponding message.
* `body` contains the newly edited content.
* For media messages, only the caption can be edited. The attached media file remains unchanged.
* `mediaUrl` therefore remains the same as the original message.
* The corresponding message record is updated to edited on the Antryk side.

### 4. `message_revoked` — App Message Deleted

The `message_revoked` event is fired when your staff deletes a message previously sent from the WhatsApp Business app.

```json theme={null}
{
  "event": "message_revoked",
  "from": "16505551111",
  "to": "16315551181",
  "messageId": "e5f6g7h8-internal-uuid",
  "waMessageId": "wamid.HBgLMTYzMTU1NTExODEVAgARGBI5...",
  "messageType": "text",
  "body": "Yep, shipped this morning!",
  "mediaUrl": null,
  "timestamp": "2026-08-21T09:16:30.000Z",
  "phoneNumberId": "123456123",
  "wabaId": "987654987",
  "contact": null
}
```

#### Field Notes

* `waMessageId` identifies the message that was deleted.
* `body` contains the last known content before the message was deleted.
* If the message was previously edited, the `body` represents the latest known content.
* The corresponding Antryk message record is marked with the status revoked.

### 5. `message_status` — Delivery Status Change

The `message_status` event is fired when a message sent through the API or WhatsApp Business app changes its delivery state.

```json theme={null}
{
  "event": "message_status",
  "status": "delivered",
  "waMessageId": "wamid.HBgLMTYzMTU1NTExODEVAgARGBI5...",
  "messageId": "e5f6g7h8-internal-uuid",
  "customerNumber": "16315551181",
  "timestamp": "2026-08-21T09:14:30.000Z",
  "phoneNumberId": "123456123",
  "wabaId": "987654987"
}
```

#### Supported Status Values

* `sent`
* `delivered`
* `read`
* `failed`

A single WhatsApp message can generate multiple status events as it progresses through its delivery lifecycle.

For example:

`sent` → `delivered` → `read`

Each status transition can result in a separate webhook request.

Failed messages may include additional error information in the Antryk dashboard and logs.

***

## Common Webhook Fields Reference

| Field           | Type            | Description                                                                                            |
| --------------- | --------------- | ------------------------------------------------------------------------------------------------------ |
| `event`         | string          | Event type such as `message`, `message_echo`, `message_edited`, `message_revoked`, or `message_status` |
| `status`        | string          | Delivery state for `message_status`: `sent`, `delivered`, `read`, or `failed`                          |
| `from`          | string          | Sender phone number in E.164 format without `+`                                                        |
| `to`            | string          | Recipient phone number                                                                                 |
| `messageId`     | string (UUID)   | Antryk internal message record ID                                                                      |
| `waMessageId`   | string          | WhatsApp message ID used to correlate messages                                                         |
| `messageType`   | string          | Message type such as `text`, `image`, `audio`, `video`, `document`, or `template`                      |
| `body`          | string \| null  | Message text or media caption                                                                          |
| `mediaUrl`      | string \| null  | Permanent media URL once the media has been downloaded and resolved                                    |
| `timestamp`     | ISO 8601 string | Time when the event or message was recorded                                                            |
| `phoneNumberId` | string          | WhatsApp Business phone number ID                                                                      |
| `wabaId`        | string          | WhatsApp Business Account ID                                                                           |
| `contact`       | object \| null  | Customer WhatsApp profile information for incoming message events                                      |

***

## Webhook Retry & Delivery Behavior

Antryk automatically retries webhook delivery when your callback endpoint fails.

For reliable webhook processing:

* Return a 2xx response quickly.
* Keep webhook processing asynchronous where possible.
* Avoid long-running operations inside the webhook request.
* Make your webhook handler idempotent.
* Use `waMessageId` to identify and deduplicate WhatsApp messages.
* Monitor failed webhook requests from the Webhook Audit Logs.

If your endpoint remains unreachable after all retry attempts, the event is recorded in Antryk logs but is not queued indefinitely.

Slow responses can be treated as failed deliveries and may result in retry attempts and duplicate webhook requests.

***

## Webhook Security Best Practices

Webhook endpoints should be treated as public-facing API endpoints.

Follow these security practices:

* Keep your Signing Secret private.
* Store the secret in environment variables or a secure secrets manager.
* Never expose the secret in frontend code.
* Always validate the `X-Webhook-Signature` header.
* Reject requests with invalid signatures.
* Use HTTPS for your Callback URL.
* Return a 401 response when signature verification fails.
* Use `waMessageId` to prevent duplicate message processing.
* Keep webhook processing fast and asynchronous where possible.
* Monitor webhook failures through Antryk Webhook Audit Logs.

Before using your webhook in production, test the integration from the Antryk dashboard.

If the test fails, inspect your webhook logs for:

* HTTP status codes
* Request attempts
* Target URL
* Request payload
* Authentication errors
* Server errors
* Connection failures

***

## Troubleshooting Webhook Issues

### Webhook returns 401

A 401 response usually indicates that signature verification failed.

Check:

* The Signing Secret in your environment matches the Antryk dashboard configuration.
* Your backend is reading the `X-Webhook-Signature` header correctly.
* Your HMAC algorithm is SHA-256.
* The `sha256=` prefix is included in the comparison.
* The payload used for signature calculation matches the request payload.

### Webhook requests are repeated

Repeated webhook requests can occur when Antryk does not receive a successful response from your endpoint.

Check:

* Your endpoint returns a 2xx response.
* Your server responds quickly.
* Your endpoint is publicly reachable.
* Your webhook handler does not take too long to process events.

Your application should be idempotent and use `waMessageId` where applicable to prevent duplicate processing.

### Webhook endpoint is not receiving requests

Check:

* The Callback URL is correct.
* The URL uses HTTPS.
* Your server is publicly accessible.
* Your route accepts POST requests.
* Your firewall or reverse proxy allows the request.
* Your server is returning a response.
* The Send Test Event feature works correctly.

***

## Webhook Audit Logs

Antryk provides Webhook Audit Logs to help developers monitor webhook delivery and troubleshoot integration issues.

The audit log provides visibility into webhook delivery attempts made by Antryk.

### Webhook Log Information

| Column      | Description                                     |
| ----------- | ----------------------------------------------- |
| Date & Time | Time when the webhook delivery attempt occurred |
| Event ID    | Unique identifier for the webhook event         |
| Status      | HTTP response status such as 200 or 401         |
| Attempts    | Number of delivery attempts                     |
| Result      | Whether the delivery was successful or failed   |

### Webhook Log Details

Clicking a webhook audit log opens a detail drawer containing additional information about the delivery attempt.

Log details can include:

* Event information
* Delivery status
* Attempt information
* Target URL
* Request payload
* Response information
* Debugging details

These logs make it easier to diagnose authentication failures, unreachable endpoints, invalid responses, and other webhook integration problems.
