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

# Event Webhooks

> Receive real-time notifications when calls complete, leads are created, bookings happen, and customers change subscription preferences

## Overview

Avoca can push events to your systems in real time via HTTPS webhooks. Webhook configurations are managed per team (or enterprise-wide) and deliver signed JSON payloads to an endpoint you control.

<Note>
  Event webhooks are the push counterpart to the [v1 leads feed](/api-reference/introduction) — consumers can join the webhook stream to pulled lead records on `id` / `external_id`.
</Note>

## Event Types

| Event                                       | Fires when                                                                            |
| ------------------------------------------- | ------------------------------------------------------------------------------------- |
| `voice_call.completed`                      | A call ends and has been classified and saved                                         |
| `lead.created`                              | A new lead is recorded (from any intake source)                                       |
| `lead.booking_created`                      | A booking is created for a lead — one event per distinct CRM job                      |
| `lead.completed`                            | A lead reaches the true end of its lifecycle (booked, unbooked, opted out, or failed) |
| `customer.communication_preference_changed` | A customer opts in or out of SMS (STOP/START)                                         |

See [Event Payloads](/api-reference/webhooks/event-payloads) for the full schema of each event.

## Configuration

Webhook configurations are managed from the Avoca dashboard (or via the team-scoped configuration API):

* **Name** — a label for the configuration
* **Endpoint URL** — your HTTPS endpoint (max 2048 chars; `https://` required)
* **Events** — which event types to subscribe to (at least one)
* **Custom headers** — optional name/value pairs sent on every delivery; individual headers can be marked *encrypted* (stored AES-GCM encrypted, never returned in plaintext)
* **Include transcript / recording URL** — opt-in flags controlling optional fields on `voice_call.completed` payloads
* **Lead source filter** — optionally restrict `lead.*` events to specific lead sources

You can create a configuration in a disabled state with no endpoint to obtain the signing secret first, then enable it once your receiver is deployed. Each configuration also supports a **test event** so you can verify your receiver end to end.

## Verifying Signatures

Every delivery is signed with the configuration's webhook secret using HMAC-SHA256:

| Header                | Contents                                                     |
| --------------------- | ------------------------------------------------------------ |
| `X-Webhook-Signature` | `sha256=<hex HMAC-SHA256 of the request body>`               |
| `X-Webhook-Timestamp` | ISO 8601 timestamp of this delivery attempt                  |
| `X-Avoca-Event`       | The event type (e.g. `lead.created`)                         |
| `X-Avoca-Event-Id`    | Delivery ID (UUID) — stable across retries of the same event |
| `X-Avoca-Delivery`    | Same as the event ID                                         |

Compute the HMAC of the raw request body with your webhook secret and compare against `X-Webhook-Signature` using a constant-time comparison. The timestamp and signature are regenerated on each retry attempt, so also check `X-Webhook-Timestamp` freshness to reject replays.

```javascript theme={null}
import crypto from 'node:crypto';

function verify(req, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(req.rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(req.headers['x-webhook-signature'] ?? '')
  );
}
```

## Delivery & Retries

* Deliveries are `POST` requests with `Content-Type: application/json` and a **10-second timeout**.
* Failed deliveries are retried **5 times with exponential backoff**. `4xx` responses are treated as non-retriable (a misconfigured endpoint won't be hammered); `5xx` and network errors are retried.
* Use `X-Avoca-Event-Id` for idempotency — it is stable across retries of the same event.
* **Auto-pause:** after 50 consecutive failures a configuration is automatically disabled (`disabled_reason: auto_paused_consecutive_failures`). Any successful (2xx) delivery resets the counter. Re-enable from the dashboard once your endpoint is healthy.
* Delivery logs are retained for 90 days.

## Respond Quickly

Return a `2xx` as soon as you have durably received the event, and process asynchronously. Anything slower than 10 seconds counts as a failed attempt.
