# Webhooks

> Endpoints, signing secrets, deliveries and replay.

Canonical: https://docs.whabuzz.com/api/webhooks/

Endpoints, signing secrets, deliveries and replay.

Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer <key>` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md).

Operations on this page:

- [`GET /v1/webhooks`](#listWebhookEndpoints): List endpoints
- [`POST /v1/webhooks`](#createWebhookEndpoint): Add an endpoint
- [`GET /v1/webhooks/{endpoint_id}`](#getWebhookEndpoint): Get an endpoint
- [`PATCH /v1/webhooks/{endpoint_id}`](#updateWebhookEndpoint): Change URL, event types, description or status
- [`DELETE /v1/webhooks/{endpoint_id}`](#deleteWebhookEndpoint): Delete an endpoint
- [`POST /v1/webhooks/{endpoint_id}/verify`](#verifyWebhookEndpoint): Send the verify ping again
- [`POST /v1/webhooks/{endpoint_id}/rotate-secret`](#rotateWebhookSecret): Rotate the signing secret
- [`POST /v1/webhooks/{endpoint_id}/replay`](#bulkReplay): Re-send deliveries in a time range
- [`GET /v1/webhook-deliveries`](#listDeliveries): List deliveries
- [`GET /v1/webhook-deliveries/{delivery_id}`](#getDelivery): Get a delivery with its attempt log
- [`POST /v1/webhook-deliveries/{delivery_id}/replay`](#replayDelivery): Re-send one delivery now

## List endpoints {#listWebhookEndpoints}

`GET /v1/webhooks`

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listWebhookEndpoints`.

cURL:

```bash
curl -X GET "https://api.whabuzz.com/v1/webhooks" \
  -H "Authorization: Bearer $WHABUZZ_KEY"
```

**Responses**

**200** Endpoints

```json
{
  "data": [
    {
      "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
      "url": "https://api.example.com/whatsapp/events",
      "event_types": [
        "*"
      ],
      "status": "active",
      "verified_at": "2026-10-16T09:20:00Z",
      "secret_prefix": "whsec_EXAMPLESECRET0000",
      "consecutive_failures": 0
    }
  ]
}
```

## Add an endpoint {#createWebhookEndpoint}

`POST /v1/webhooks`

WhaBuzz sends a verify ping right away. Your endpoint must answer 2xx with the `challenge`
(plain text, or JSON `{"challenge":"…"}`). Until an endpoint passes, your numbers are not
`connected`. The signing secret is in this response only.

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `createWebhookEndpoint`.

**Request body** (`application/json`, required)

| Field | Type | Required | Description |
|---|---|---|---|
| `url` | string (uri) | yes |  |
| `description` | string | no |  |
| `event_types` | array of *` or `message.inbound` or `message.status` or `message.error` or `message.echo` or `message.outbound` or `user.preferences` or `batch.completed` or `template.status` or `template.quality` or `template.category` or `number.quality` or `number.name` or `number.connection` or `account.update` or `account.alerts` or `account.capability` or `account.security` or `token.expiring` or `token.invalid` or `meta.other | no | Default `["*"]`. |

Request example:

```json
{
  "url": "https://api.example.com/whatsapp/events",
  "event_types": [
    "*"
  ]
}
```

cURL:

```bash
curl -X POST "https://api.whabuzz.com/v1/webhooks" \
  -H "Authorization: Bearer $WHABUZZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://api.example.com/whatsapp/events",
  "event_types": [
    "*"
  ]
}'
```

**Responses**

**201** Created and verified

```json
{
  "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
  "url": "https://api.example.com/whatsapp/events",
  "event_types": [
    "*"
  ],
  "status": "active",
  "verified_at": "2026-10-16T09:20:00Z",
  "secret": "whsec_EXAMPLESECRET0000000000000000",
  "secret_prefix": "whsec_EXAMPLESECRET0000"
}
```

**422** Created, but the verify ping failed. The endpoint stays pending; fix it and call verify.

```json
{
  "source": "whabuzz",
  "error": {
    "code": "webhook_verify_failed",
    "message": "Endpoint answered 200 without the challenge",
    "details": {
      "endpoint_id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
      "http_status": 200,
      "body_excerpt": "OK",
      "secret": "whsec_EXAMPLESECRET0000000000000000"
    }
  },
  "request_id": "req_01JAB3W1Z4B7D0F3H6K9N2Q5S8"
}
```

## Get an endpoint {#getWebhookEndpoint}

`GET /v1/webhooks/{endpoint_id}`

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getWebhookEndpoint`.

**Parameters**

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `endpoint_id` | path | string (uuid) | yes |  |

cURL:

```bash
curl -X GET "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID" \
  -H "Authorization: Bearer $WHABUZZ_KEY"
```

**Responses**

**200** Endpoint

```json
{
  "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
  "url": "https://api.example.com/whatsapp/events",
  "description": "Production",
  "event_types": [
    "*"
  ],
  "status": "active",
  "verified_at": "2026-10-16T09:20:00Z",
  "secret_prefix": "whsec_EXAMPLESECRET0000",
  "previous_secret_expires_at": null,
  "last_success_at": "2026-10-16T10:02:11Z",
  "consecutive_failures": 0
}
```

## Change URL, event types, description or status {#updateWebhookEndpoint}

`PATCH /v1/webhooks/{endpoint_id}`

Changing `url` re-runs the verify ping.

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `updateWebhookEndpoint`.

**Parameters**

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `endpoint_id` | path | string (uuid) | yes |  |

**Request body** (`application/json`, required)

Request example:

```json
{
  "event_types": [
    "message.inbound",
    "message.status"
  ],
  "status": "active"
}
```

cURL:

```bash
curl -X PATCH "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID" \
  -H "Authorization: Bearer $WHABUZZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "event_types": [
    "message.inbound",
    "message.status"
  ],
  "status": "active"
}'
```

**Responses**

**200** Updated

```json
{
  "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
  "event_types": [
    "message.inbound",
    "message.status"
  ],
  "status": "active"
}
```

## Delete an endpoint {#deleteWebhookEndpoint}

`DELETE /v1/webhooks/{endpoint_id}`

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `deleteWebhookEndpoint`.

**Parameters**

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `endpoint_id` | path | string (uuid) | yes |  |

cURL:

```bash
curl -X DELETE "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID" \
  -H "Authorization: Bearer $WHABUZZ_KEY"
```

**Responses**

**200** Deleted

```json
{
  "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
  "deleted": true
}
```

## Send the verify ping again {#verifyWebhookEndpoint}

`POST /v1/webhooks/{endpoint_id}/verify`

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `verifyWebhookEndpoint`.

**Parameters**

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `endpoint_id` | path | string (uuid) | yes |  |

cURL:

```bash
curl -X POST "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID/verify" \
  -H "Authorization: Bearer $WHABUZZ_KEY"
```

**Responses**

**200** Passed

```json
{
  "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
  "status": "active",
  "verified_at": "2026-10-16T09:25:00Z",
  "response_ms": 84
}
```

**422** Failed

```json
{
  "source": "whabuzz",
  "error": {
    "code": "webhook_verify_failed",
    "message": "Endpoint timed out after 5000 ms",
    "details": {
      "http_status": null
    }
  },
  "request_id": "req_01JAB3X2A5C8E1G4J7M0P3S6U9"
}
```

## Rotate the signing secret {#rotateWebhookSecret}

`POST /v1/webhooks/{endpoint_id}/rotate-secret`

Both secrets sign every delivery until `previous_secret_expires_at`, so you can deploy the new one without dropping events.

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `rotateWebhookSecret`.

**Parameters**

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `endpoint_id` | path | string (uuid) | yes |  |

**Request body** (`application/json`)

| Field | Type | Required | Description |
|---|---|---|---|
| `overlap_hours` | integer | no | Default `24`. Range 0..168. |

Request example:

```json
{
  "overlap_hours": 24
}
```

cURL:

```bash
curl -X POST "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID/rotate-secret" \
  -H "Authorization: Bearer $WHABUZZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "overlap_hours": 24
}'
```

**Responses**

**200** New secret (shown once)

```json
{
  "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
  "secret": "whsec_EXAMPLESECRET0000000000000000",
  "secret_prefix": "whsec_EXAMPLESECRET0000",
  "previous_secret_expires_at": "2026-10-17T09:30:00Z"
}
```

## Re-send deliveries in a time range {#bulkReplay}

`POST /v1/webhooks/{endpoint_id}/replay`

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `bulkReplay`.

**Parameters**

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `endpoint_id` | path | string (uuid) | yes |  |

**Request body** (`application/json`, required)

| Field | Type | Required | Description |
|---|---|---|---|
| `from` | string (date-time) | yes |  |
| `to` | string (date-time) | yes |  |
| `status` | array of delivered` or `failed` or `dead | no | Default `["failed","dead"]`. |
| `event_types` | array of *` or `message.inbound` or `message.status` or `message.error` or `message.echo` or `message.outbound` or `user.preferences` or `batch.completed` or `template.status` or `template.quality` or `template.category` or `number.quality` or `number.name` or `number.connection` or `account.update` or `account.alerts` or `account.capability` or `account.security` or `token.expiring` or `token.invalid` or `meta.other | no |  |

Request example:

```json
{
  "from": "2026-10-16T00:00:00Z",
  "to": "2026-10-16T06:00:00Z",
  "status": [
    "dead"
  ]
}
```

cURL:

```bash
curl -X POST "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID/replay" \
  -H "Authorization: Bearer $WHABUZZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "from": "2026-10-16T00:00:00Z",
  "to": "2026-10-16T06:00:00Z",
  "status": [
    "dead"
  ]
}'
```

**Responses**

**202** Queued

```json
{
  "queued": 312
}
```

## List deliveries {#listDeliveries}

`GET /v1/webhook-deliveries`

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listDeliveries`.

**Parameters**

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `endpoint_id` | query | string (uuid) | no |  |
| `status` | query | `pending` or `delivered` or `failed` or `dead` | no |  |
| `event_id` | query | string | no |  |
| `from` | query | string (date-time) | no |  |
| `to` | query | string (date-time) | no |  |
| `limit` | query | integer | no |  |
| `cursor` | query | string | no | `next_cursor` from the previous page. |

cURL:

```bash
curl -X GET "https://api.whabuzz.com/v1/webhook-deliveries" \
  -H "Authorization: Bearer $WHABUZZ_KEY"
```

**Responses**

**200** Deliveries

```json
{
  "data": [
    {
      "id": "dlv_01JAB3Y3B6D9F2H5K8N1Q4T7W0",
      "event_id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ",
      "event_type": "message.inbound",
      "endpoint_id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
      "status": "failed",
      "attempts": 3,
      "last_http_status": 503,
      "next_attempt_at": "2026-10-16T05:15:03Z"
    }
  ],
  "next_cursor": "dlv_01JAB3Y3B6D9F2H5K8N1Q4T7W0"
}
```

## Get a delivery with its attempt log {#getDelivery}

`GET /v1/webhook-deliveries/{delivery_id}`

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getDelivery`.

**Parameters**

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `delivery_id` | path | string | yes |  |

cURL:

```bash
curl -X GET "https://api.whabuzz.com/v1/webhook-deliveries/$DELIVERY_ID" \
  -H "Authorization: Bearer $WHABUZZ_KEY"
```

**Responses**

**200** Delivery

```json
{
  "id": "dlv_01JAB3Y3B6D9F2H5K8N1Q4T7W0",
  "event_id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ",
  "event_type": "message.inbound",
  "endpoint_id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c",
  "status": "failed",
  "attempts": 3,
  "last_http_status": 503,
  "last_error": "http_5xx",
  "next_attempt_at": "2026-10-16T05:15:03Z",
  "attempt_log": [
    {
      "at": "2026-10-16T05:12:03Z",
      "http_status": null,
      "ms": 3000,
      "error": "timeout"
    },
    {
      "at": "2026-10-16T05:13:00Z",
      "http_status": 503,
      "ms": 41,
      "error": "http_5xx"
    },
    {
      "at": "2026-10-16T05:14:00Z",
      "http_status": 503,
      "ms": 38,
      "error": "http_5xx"
    }
  ],
  "is_replay": false
}
```

## Re-send one delivery now {#replayDelivery}

`POST /v1/webhook-deliveries/{delivery_id}/replay`

One synchronous attempt with today's secrets. Works within your retention window.

**Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `replayDelivery`.

**Parameters**

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `delivery_id` | path | string | yes |  |

cURL:

```bash
curl -X POST "https://api.whabuzz.com/v1/webhook-deliveries/$DELIVERY_ID/replay" \
  -H "Authorization: Bearer $WHABUZZ_KEY"
```

**Responses**

**200** The new delivery

```json
{
  "id": "dlv_01JAB3Z4C7E0G3J6M9P2S5V8Y1",
  "status": "delivered",
  "attempts": 1,
  "last_http_status": 200,
  "last_response_ms": 92,
  "is_replay": true,
  "replay_of": "dlv_01JAB3Y3B6D9F2H5K8N1Q4T7W0"
}
```

**404** Unknown delivery, or the event body is past retention

```json
{
  "source": "whabuzz",
  "error": {
    "code": "not_found",
    "message": "Event body expired under the tenant's 90-day retention",
    "details": {
      "reason": "payload_expired"
    }
  },
  "request_id": "req_01JAB40A5D8F1H4K7N0Q3T6W9Z"
}
```
