# Адреса вебхуков

Адреса вебхуков кабинета, их состояние и журнал доставок. Нужны право `webhooks:read` и ключ на все пространства и кампании.

Базовый адрес: https://api.melioralab.io/v1. Ключ передается в заголовке `Authorization: Bearer mel_live_...`.

Маршруты:

- `GET /v1/webhook-endpoints`: Список адресов вебхуков
- `GET /v1/webhook-endpoints/{id}`: Получить адрес вебхука
- `GET /v1/webhook-endpoints/{id}/deliveries`: Журнал доставок

## Объект WebhookEndpoint

Адрес вебхука кабинета и его состояние. Полного адреса нет: в пути бывает секрет, поэтому видно только имя сервера. Значений дополнительных заголовков тоже нет, только их имена.

| Поле | Тип | Описание |
|---|---|---|
| `object` | string | Тип объекта, всегда `webhook_endpoint`. |
| `id` | string (uuid) | Идентификатор адреса. |
| `status` | string | `active` получает события, `paused` на паузе, `disabled` выключен: сам или по коду 410 получателя. Значения: `active`, `paused`, `disabled`. |
| `disabled_reason` | string или null | Почему адрес выключен или на паузе: `gone` (получатель ответил 410), `failing_72h` (ошибки больше 3 суток), `plan` (тариф без вебхуков), `other`. У работающего адреса `null`. Значения: `gone`, `failing_72h`, `plan`, `other`. |
| `host` | string | Имя сервера получателя. |
| `description` | string или null | Описание из кабинета или `null`. |
| `event_types` | array of string | Типы событий, которые получает адрес. |
| `workspace_ids` | array of string или null | Пространства, события которых получает адрес. `null`: все пространства. |
| `campaign_ids` | array of string или null | Кампании, события которых получает адрес. `null`: все кампании. |
| `include_message_text` | boolean | Передается ли текст ответа лида. |
| `header_names` | array of string | Имена дополнительных заголовков, без значений. |
| `failing_since` | string (date-time) или null | С какого момента адрес не принимает события или `null`, если последняя попытка успешна. |
| `consecutive_failures` | integer | Неудачных попыток подряд. |
| `last_success_at` | string (date-time) или null | Время последней успешной доставки или `null`. |
| `version` | integer | Номер версии настроек адреса. Растет при каждом изменении. |
| `created_at` | string (date-time) | Когда адрес добавлен. |
| `updated_at` | string (date-time) | Когда настройки адреса менялись последний раз. |
| `deliveries` | object | Сводка доставок. |
| `deliveries.pending` | integer | Сколько событий ждут отправки. |
| `deliveries.succeeded_24h` | integer | Доставлено за последние сутки. |
| `deliveries.failed_24h` | integer | Не доставлено за последние сутки. |
| `deliveries.last_finished_at` | string (date-time) или null | Когда закончилась последняя доставка или `null`. |
| `deliveries.last_status_code` | integer или null | Код ответа получателя на последнюю доставку или `null`. |
| `deliveries.last_error_class` | string или null | Класс последней ошибки: `invalid_url`, `dns`, `ssrf_blocked`, `connect`, `tls`, `timeout`, `http`, `payload_too_large`, `unknown` или `null`. Значения: `invalid_url`, `dns`, `ssrf_blocked`, `connect`, `tls`, `timeout`, `http`, `payload_too_large`, `unknown`. |

Пример:

```json
{
  "object": "webhook_endpoint",
  "id": "6b2d9f40-3c1e-4a7b-8f5d-2e9c0a1b7d64",
  "status": "active",
  "disabled_reason": null,
  "host": "hooks.example.com",
  "description": "CRM",
  "event_types": [
    "lead.first_message_sent",
    "lead.replied"
  ],
  "workspace_ids": null,
  "campaign_ids": null,
  "include_message_text": false,
  "header_names": [
    "x-api-key"
  ],
  "failing_since": null,
  "consecutive_failures": 0,
  "last_success_at": "2026-10-27T09:15:03.000Z",
  "version": 2,
  "created_at": "2026-10-20T08:00:00.000Z",
  "updated_at": "2026-10-22T12:30:00.000Z",
  "deliveries": {
    "pending": 0,
    "succeeded_24h": 38,
    "failed_24h": 0,
    "last_finished_at": "2026-10-27T09:15:03.000Z",
    "last_status_code": 200,
    "last_error_class": null
  }
}
```

## Объект WebhookDelivery

Одна доставка события на адрес вебхука. Данных лида нет: само событие отдает лента событий по `event_id`.

| Поле | Тип | Описание |
|---|---|---|
| `object` | string | Тип объекта, всегда `webhook_delivery`. |
| `id` | string (uuid) | Идентификатор доставки. |
| `endpoint_id` | string (uuid) | Адрес вебхука. |
| `event_id` | string | Идентификатор события: тот же, что в заголовке `webhook-id` и в ленте событий. |
| `event_type` | string или null | Тип события, `webhook.test` для проверочного, `unknown` для неизвестного или `null`, если события уже нет. Значения: `lead.first_message_sent`, `lead.replied`, `message.received`, `lead.status_changed`, `campaign.status_changed`, `account.status_changed`, `message.sent`, `message.delivery_unknown`, `webhook.test`, `unknown`. |
| `status` | string | `pending` ждет отправки, `delivering` отправляется, `succeeded` доставлено, `failed` не доставлено, `cancelled` отменено. Значения: `pending`, `delivering`, `succeeded`, `failed`, `cancelled`, `unknown`. |
| `cancel_reason` | string или null | Почему доставка отменена: `scope_changed`, `endpoint_deleted`, `expired`, `other`. У неотмененной `null`. Значения: `scope_changed`, `endpoint_deleted`, `expired`, `other`. |
| `attempt` | integer | Сколько было попыток. |
| `next_attempt_at` | string (date-time) или null | Когда следующая попытка. Только у `pending`, иначе `null`. |
| `last_status_code` | integer или null | Код ответа получателя на последнюю попытку или `null`. |
| `last_error_class` | string или null | Класс ошибки последней попытки или `null`. Значения: `invalid_url`, `dns`, `ssrf_blocked`, `connect`, `tls`, `timeout`, `http`, `payload_too_large`, `unknown`. |
| `last_duration_ms` | integer или null | Длительность последней попытки в миллисекундах или `null`. |
| `created_at` | string (date-time) | Когда событие поставлено на доставку. |
| `finished_at` | string (date-time) или null | Когда доставка закончилась или `null`. |

Пример:

```json
{
  "object": "webhook_delivery",
  "id": "7c4e1a85-2d9b-4f63-a0e8-5b3f9c7d2e16",
  "endpoint_id": "6b2d9f40-3c1e-4a7b-8f5d-2e9c0a1b7d64",
  "event_id": "evt_1f8a3c5e7b9d4a2c6e0f8b1d3a5c7e9f",
  "event_type": "lead.replied",
  "status": "succeeded",
  "cancel_reason": null,
  "attempt": 1,
  "next_attempt_at": null,
  "last_status_code": 200,
  "last_error_class": null,
  "last_duration_ms": 184,
  "created_at": "2026-10-27T09:15:02.000Z",
  "finished_at": "2026-10-27T09:15:03.000Z"
}
```

## Список адресов вебхуков

`GET /v1/webhook-endpoints`

Адреса вебхуков кабинета и их состояние: принимают ли события, с какого момента ошибки, последняя ошибка и доставки за сутки, от старых к новым. Нужен ключ на все пространства и кампании: вебхуки общие для кабинета.

Право: `webhooks:read`. Вес запроса: 1.

### Параметры

| Параметр | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
| `limit` | строка запроса | integer | нет | Сколько объектов вернуть на странице. От 1 до 100. По умолчанию `50`. |
| `cursor` | строка запроса | string | нет | Значение `next_cursor` из предыдущего ответа. Остальные фильтры должны совпадать с первым запросом. |
| `status` | строка запроса | string | нет | Только адреса в этом состоянии. Значения: `active`, `paused`, `disabled`. |

### Ответ

Список: `object`, `data`, `has_more`, `next_cursor`. Пагинация: https://docs.melioralab.io/md/pagination.md

### Особые ошибки

- `cursor_mismatch` (400): Курсор поврежден, выдан для другого маршрута или фильтров, либо права и охват ключа изменились.
- `scope_required` (403): Ключ не разрешает операцию. Для команды нужно право ее вида.
- `not_found` (404): Объект не найден или находится вне охвата ключа. Неизвестный путь тоже дает 404.
- `cursor_expired` (410): Срок курсора истек: 15 минут для списков, 30 суток для ленты событий.

Общие ошибки: https://docs.melioralab.io/md/errors.md

### Пример запроса

```bash
curl https://api.melioralab.io/v1/webhook-endpoints \
  -H "Authorization: Bearer $MELIORA_API_KEY"
```

### Пример ответа

```json
{
  "object": "list",
  "data": [
    {
      "object": "webhook_endpoint",
      "id": "6b2d9f40-3c1e-4a7b-8f5d-2e9c0a1b7d64",
      "status": "active",
      "disabled_reason": null,
      "host": "hooks.example.com",
      "description": "CRM",
      "event_types": [
        "lead.first_message_sent",
        "lead.replied"
      ],
      "workspace_ids": null,
      "campaign_ids": null,
      "include_message_text": false,
      "header_names": [
        "x-api-key"
      ],
      "failing_since": null,
      "consecutive_failures": 0,
      "last_success_at": "2026-10-27T09:15:03.000Z",
      "version": 2,
      "created_at": "2026-10-20T08:00:00.000Z",
      "updated_at": "2026-10-22T12:30:00.000Z",
      "deliveries": {
        "pending": 0,
        "succeeded_24h": 38,
        "failed_24h": 0,
        "last_finished_at": "2026-10-27T09:15:03.000Z",
        "last_status_code": 200,
        "last_error_class": null
      }
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

## Получить адрес вебхука

`GET /v1/webhook-endpoints/{id}`

Один адрес вебхука по идентификатору. Удаленный адрес дает 404.

Право: `webhooks:read`. Вес запроса: 1.

### Параметры

| Параметр | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
| `id` | путь | string (uuid) | да | Идентификатор адреса вебхука. |

### Ответ

Объект `WebhookEndpoint`.

### Особые ошибки

- `scope_required` (403): Ключ не разрешает операцию. Для команды нужно право ее вида.
- `not_found` (404): Объект не найден или находится вне охвата ключа. Неизвестный путь тоже дает 404.

Общие ошибки: https://docs.melioralab.io/md/errors.md

### Пример запроса

```bash
curl https://api.melioralab.io/v1/webhook-endpoints/ \
  -H "Authorization: Bearer $MELIORA_API_KEY"
```

### Пример ответа

```json
{
  "object": "webhook_endpoint",
  "id": "6b2d9f40-3c1e-4a7b-8f5d-2e9c0a1b7d64",
  "status": "active",
  "disabled_reason": null,
  "host": "hooks.example.com",
  "description": "CRM",
  "event_types": [
    "lead.first_message_sent",
    "lead.replied"
  ],
  "workspace_ids": null,
  "campaign_ids": null,
  "include_message_text": false,
  "header_names": [
    "x-api-key"
  ],
  "failing_since": null,
  "consecutive_failures": 0,
  "last_success_at": "2026-10-27T09:15:03.000Z",
  "version": 2,
  "created_at": "2026-10-20T08:00:00.000Z",
  "updated_at": "2026-10-22T12:30:00.000Z",
  "deliveries": {
    "pending": 0,
    "succeeded_24h": 38,
    "failed_24h": 0,
    "last_finished_at": "2026-10-27T09:15:03.000Z",
    "last_status_code": 200,
    "last_error_class": null
  }
}
```

## Журнал доставок

`GET /v1/webhook-endpoints/{id}/deliveries`

Доставки событий на один адрес, от новых к старым: состояние, попытки, код ответа и ошибка. Помогает понять, почему CRM не получила событие. Само событие отдает лента событий по `event_id`.

Право: `webhooks:read`. Вес запроса: 2.

### Параметры

| Параметр | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
| `id` | путь | string (uuid) | да | Идентификатор адреса вебхука. |
| `limit` | строка запроса | integer | нет | Сколько объектов вернуть на странице. От 1 до 100. По умолчанию `50`. |
| `cursor` | строка запроса | string | нет | Значение `next_cursor` из предыдущего ответа. Остальные фильтры должны совпадать с первым запросом. |
| `status` | строка запроса | string | нет | Только доставки в этом состоянии. Значения: `pending`, `delivering`, `succeeded`, `failed`, `cancelled`. |

### Ответ

Список: `object`, `data`, `has_more`, `next_cursor`. Пагинация: https://docs.melioralab.io/md/pagination.md

### Особые ошибки

- `cursor_mismatch` (400): Курсор поврежден, выдан для другого маршрута или фильтров, либо права и охват ключа изменились.
- `scope_required` (403): Ключ не разрешает операцию. Для команды нужно право ее вида.
- `not_found` (404): Объект не найден или находится вне охвата ключа. Неизвестный путь тоже дает 404.
- `cursor_expired` (410): Срок курсора истек: 15 минут для списков, 30 суток для ленты событий.

Общие ошибки: https://docs.melioralab.io/md/errors.md

### Пример запроса

```bash
curl https://api.melioralab.io/v1/webhook-endpoints//deliveries \
  -H "Authorization: Bearer $MELIORA_API_KEY"
```

### Пример ответа

```json
{
  "object": "list",
  "data": [
    {
      "object": "webhook_delivery",
      "id": "7c4e1a85-2d9b-4f63-a0e8-5b3f9c7d2e16",
      "endpoint_id": "6b2d9f40-3c1e-4a7b-8f5d-2e9c0a1b7d64",
      "event_id": "evt_1f8a3c5e7b9d4a2c6e0f8b1d3a5c7e9f",
      "event_type": "lead.replied",
      "status": "succeeded",
      "cancel_reason": null,
      "attempt": 1,
      "next_attempt_at": null,
      "last_status_code": 200,
      "last_error_class": null,
      "last_duration_ms": 184,
      "created_at": "2026-10-27T09:15:02.000Z",
      "finished_at": "2026-10-27T09:15:03.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "v1.k1.Qm9hcmRfMWZ4.c3RyaWN0bHlfb3BhcXVl.dGFnX2V4YW1wbGU.bWFjX2V4YW1wbGVfdmFsdWU"
}
```
