# Webhook events

Every webhook event Vocenya sends, the scope each one needs and an example payload for each.

Subscribe an endpoint to the events you need. Each event needs your key's `webhooks:manage` scope plus the read scope of its record. All events share the envelope `{"id", "type", "livemode", "created_at", "data"}` described in [Webhooks](https://vocenya.com/docs/webhooks); `data` differs per event.

| Event | When it is sent | Scopes needed to subscribe |
| --- | --- | --- |
| [`lead.created`](#lead-created) | A lead was captured | `leads:read` |
| [`call.completed`](#call-completed) | An inbound call ended | `calls:read` |
| [`booking.created`](#booking-created) | An appointment was booked | `bookings:read` |
| [`chat.handed_off`](#chat-handed-off) | A website chat was handed to a person | `chats:read` |
| [`outbound_call.completed`](#outbound-call-completed) | An outbound call ended | `outbound:write` |
| [`chat.started`](#chat-started) | A visitor started a website chat | `chats:read` |
| [`chat.message.created`](#chat-message-created) | A website chat got a new message | `chats:read` |
| [`chat.lead_captured`](#chat-lead-captured) | A website chat captured a lead | `chats:read`, `leads:read` |
| [`chat.handoff_requested`](#chat-handoff-requested) | The visitor or the AI asked for a person in a website chat | `chats:read` |
| [`chat.closed`](#chat-closed) | A website chat was closed | `chats:read` |

New event types may be added within the API version, so ignore types you do not handle.

## Call events

`call.completed` carries the call's `id`, `direction`, `status`, numbers, times, `duration_seconds` and `spam`: `true` when the receptionist judged the call unwanted (no lead is created for it). Calls from numbers on your [blocked callers list](https://vocenya.com/docs/reference/blocked-callers) never reach anyone and send no event.

## Live chat events

Every `chat.*` event carries the same `chat` object: `id`, `status`, `page_url`, `handed_off_at`, `closed_at` and `created_at`.

- `chat.message.created` adds `message`. `sender` is who wrote it (`visitor`, `ai`, `agent`, `owner` or `system`), `role` is how the widget shows it (`visitor`, `ai`, `team` or `system`) and `via_api` is `true` for replies sent with the API. To build a bot, answer visitor messages with `POST /chats/{chat}/messages` and skip `via_api: true`, which are your own.
- `chat.lead_captured` adds `lead`, with the same fields as `lead.created`.
- `chat.handoff_requested` adds `requested_by` (`visitor` or `ai`) when a person is asked for. The chat is then `with_agent` (a GH Live agent has it) or `with_owner` (waiting for your team).
- `chat.handed_off` also fires when your team takes a chat over by replying.
- `chat.closed` adds `chat.lead_id` and `chat.message_count`.

HIPAA-mode accounts receive ids only, for example `{"chat": {"id": 205}, "message": {"id": 4410}}`.

## Example payloads

These are the exact samples test deliveries send (a test delivery adds `"sample": true` to `data`).

### lead.created

A lead was captured. Subscribing needs `leads:read`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "lead.created",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "lead": {
      "id": 311,
      "call_id": 1042,
      "chat_conversation_id": null,
      "outbound_call_id": null,
      "name": "Jordan Smith",
      "phone_number": "+15555550123",
      "email": "jordan@example.com",
      "urgency": null,
      "custom_fields": [],
      "created_at": "2026-10-02T14:05:40+00:00"
    }
  }
}
```

### call.completed

An inbound call ended. Subscribing needs `calls:read`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "call.completed",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "call": {
      "id": 1042,
      "direction": "inbound",
      "status": "completed",
      "from_number": "+15555550123",
      "to_number": "+15555550199",
      "started_at": "2026-10-02T14:00:00+00:00",
      "ended_at": "2026-10-02T14:03:25+00:00",
      "duration_seconds": 205,
      "spam": false
    }
  }
}
```

### booking.created

An appointment was booked. Subscribing needs `bookings:read`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "booking.created",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "booking": {
      "id": 88,
      "call_id": 1042,
      "outbound_call_id": null,
      "provider": "google_calendar",
      "starts_at": "2026-10-05T15:30:00+00:00",
      "duration_minutes": 30,
      "name": "Jordan Smith",
      "phone_number": "+15555550123"
    }
  }
}
```

### chat.handed_off

A website chat was handed to a person. Subscribing needs `chats:read`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "chat.handed_off",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "chat": {
      "id": 205,
      "status": "with_owner",
      "page_url": "https://www.example.com/contact",
      "handed_off_at": "2026-10-02T14:06:00+00:00",
      "closed_at": null,
      "created_at": "2026-10-02T14:03:11+00:00"
    }
  }
}
```

### outbound_call.completed

An outbound call ended. Subscribing needs `outbound:write`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "outbound_call.completed",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "outbound_call": {
      "id": 57,
      "campaign_id": null,
      "source": "api",
      "purpose": "informational",
      "status": "completed",
      "contact_name": "Jordan Smith",
      "phone_number": "+15555550123",
      "blocked_reason": null,
      "answered_at": "2026-10-02T14:06:02+00:00",
      "answered_by": "human",
      "ended_at": "2026-10-02T14:08:40+00:00",
      "duration_seconds": 158
    }
  }
}
```

### chat.started

A visitor started a website chat. Subscribing needs `chats:read`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "chat.started",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "chat": {
      "id": 205,
      "status": "ai",
      "page_url": "https://www.example.com/contact",
      "handed_off_at": null,
      "closed_at": null,
      "created_at": "2026-10-02T14:03:11+00:00"
    }
  }
}
```

### chat.message.created

A website chat got a new message. Subscribing needs `chats:read`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "chat.message.created",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "chat": {
      "id": 205,
      "status": "ai",
      "page_url": "https://www.example.com/contact",
      "handed_off_at": null,
      "closed_at": null,
      "created_at": "2026-10-02T14:03:11+00:00"
    },
    "message": {
      "id": 4410,
      "sender": "visitor",
      "role": "visitor",
      "author": "Visitor",
      "body": "Hi, do you have any openings this week?",
      "via_api": false,
      "created_at": "2026-10-02T14:03:30+00:00"
    }
  }
}
```

### chat.lead_captured

A website chat captured a lead. Subscribing needs `chats:read` and `leads:read`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "chat.lead_captured",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "chat": {
      "id": 205,
      "status": "ai",
      "page_url": "https://www.example.com/contact",
      "handed_off_at": null,
      "closed_at": null,
      "created_at": "2026-10-02T14:03:11+00:00"
    },
    "lead": {
      "id": 311,
      "call_id": null,
      "chat_conversation_id": 205,
      "outbound_call_id": null,
      "name": "Jordan Smith",
      "phone_number": "+15555550123",
      "email": "jordan@example.com",
      "urgency": null,
      "custom_fields": [],
      "created_at": "2026-10-02T14:05:40+00:00"
    }
  }
}
```

### chat.handoff_requested

The visitor or the AI asked for a person in a website chat. Subscribing needs `chats:read`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "chat.handoff_requested",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "chat": {
      "id": 205,
      "status": "with_owner",
      "page_url": "https://www.example.com/contact",
      "handed_off_at": "2026-10-02T14:06:00+00:00",
      "closed_at": null,
      "created_at": "2026-10-02T14:03:11+00:00"
    },
    "requested_by": "visitor"
  }
}
```

### chat.closed

A website chat was closed. Subscribing needs `chats:read`.

```json
{
  "id": "9f0c6a1e-5b7d-4c1a-9e8f-2d3b4a5c6d7e",
  "type": "chat.closed",
  "livemode": true,
  "created_at": "2026-10-02T14:03:30+00:00",
  "data": {
    "chat": {
      "id": 205,
      "status": "closed",
      "page_url": "https://www.example.com/contact",
      "handed_off_at": "2026-10-02T14:06:00+00:00",
      "closed_at": "2026-10-02T14:20:12+00:00",
      "created_at": "2026-10-02T14:03:11+00:00",
      "lead_id": 311,
      "message_count": 14
    }
  }
}
```
