> ## Documentation Index
> Fetch the complete documentation index at: https://doc.convo.co.in/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.
</Warning>

<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.
</Tip>

***

## 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

<Steps>
  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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
      }
    ]
    ```
  </Step>
</Steps>

***

## 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.
