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

# Set Up Convo Webhooks for Real-Time WhatsApp Events

> Configure Convo webhooks to receive real-time push notifications for WhatsApp message events, contact updates, and campaign replies on your server.

Webhooks let your server receive real-time push notifications whenever something meaningful happens in Convo — a message is delivered or read, a contact is created, or a campaign reply comes in. Instead of polling the API, you register a URL and Convo sends an HTTP `POST` request to that URL the moment the event fires.

> [!WARNING]
>
> Your webhook endpoint must respond with HTTP `200` as quickly as possible. If your endpoint is slow or times out, Convo will retry the delivery. To avoid duplicate processing, acknowledge the request immediately and handle the event asynchronously in a background job or queue.

> [!TIP]
>
> During local development, use a tunneling tool like [ngrok](https://ngrok.com) or [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) to expose your local server over a public HTTPS URL without deploying.

***

## Prerequisites

Before configuring a webhook, make sure you have:

* **A Custom App in Convo** — navigate to **Dashboard → Integrations → Custom Apps** and create a new app. Custom Apps are the container that holds your webhook configuration and generates the `shared_secret` used to verify payloads.
* **A publicly accessible HTTPS URL** — WhatsApp and Convo only deliver to `https://` endpoints with a valid TLS certificate. Plain HTTP or self-signed certificates are not accepted.

***

## Configuring Your Webhook

**1. Create a Custom App**

In the Convo dashboard, go to **Integrations → Custom Apps → New App**. Give your app a descriptive name (e.g., `OrderNotifications` or `CRMSync`). You'll see a `shared_secret` value after the app is created — **copy it now** and store it securely; you'll use it to verify incoming webhook payloads.

**2. Configure your webhook URL**

In your app's settings, enter the full public HTTPS URL of the endpoint on your server that will receive webhook events (e.g., `https://your-server.com/webhook`). Convo sends a `POST` request with a JSON body to this URL for every subscribed event.

**3. Subscribe to topics**

Select the event topics your app should receive. Available topics include:

| Topic | Fires when… |
| - | - |
| `contact.created` | A new contact is added to your project |
| `message.sent` | A message is dispatched from Convo |
| `message.delivered` | A message is confirmed delivered to the device |
| `message.read` | A recipient reads a message |
| `message.failed` | A message fails to deliver |
| `message.replied` | A contact replies to a message |

Subscribe only to the topics your application needs — this keeps your endpoint traffic lean and your processing logic simple.

**4. Note your shared\_secret**

After saving the app, Convo displays a `shared_secret`. This secret is used to generate an HMAC-SHA256 signature for every webhook payload, sent as the `x-convo-signature` header. Verify this signature on every incoming request to ensure the payload genuinely came from Convo and was not tampered with in transit.

**5. List webhooks**

Confirm your webhook is registered by querying the list endpoint. Filter by your app name using the `app_name` query parameter.

```text theme={null}
GET https://connect.api-wa.co/project-apis/v1/project/{project_id}/webhook?app_name=MyApp
```

| Header | Value |
| - | - |
| `X-API-WA-Project-API-Pwd` | `YOUR_API_PASSWORD` |

**Example response**

```json theme={null}
[
  {
    "id": "627adef5f2d93aba6fa649d7",
    "app_id": "627ac3ce1b6404b276b1acae",
    "project_id": "6245d025fcb7966c46294618",
    "topics": ["contact.created"],
    "webhook_url": "https://your-server.com/webhook",
    "shared_secret": "8d008e6e505171aa...",
    "created_at": 1652219637153
  }
]
```

***

## Verifying Webhook Signatures

Always validate the `x-convo-signature` header before processing a payload. This prevents replay attacks and ensures your endpoint only acts on genuine Convo events.

```javascript Node.js theme={null}
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
  return expected === signature;
}

app.post('/webhook', express.json(), (req, res) => {
  const sig = req.headers['x-convo-signature'];
  if (!verifyWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
    return res.sendStatus(401);
  }
  // Handle the event
  console.log('Event received:', req.body);
  res.sendStatus(200);
});
```

Store your `shared_secret` in an environment variable (e.g., `WEBHOOK_SECRET`) — never hard-code it in your source code.

***

## Delete a Webhook

To remove a webhook — for example when decommissioning an integration or rotating to a new endpoint URL — send a `DELETE` request with the webhook's `id`.

```text theme={null}
DELETE https://connect.api-wa.co/project-apis/v1/project/{project_id}/webhook/{webhook_id}
```

| Header | Value |
| - | - |
| `X-API-WA-Project-API-Pwd` | `YOUR_API_PASSWORD` |

This always returns:

```json theme={null}
{
  "status": "success"
}
```

After deleting, Convo will immediately stop sending events to the associated URL. If you want to resume receiving events, register a new webhook with the updated URL using your Custom App settings.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.