# История статусов

История хранит фактические изменения статуса. Она помогает восстановить порядок изменений, а не только узнать текущее значение.

Новые возможности включаются для кабинета по запросу.

## Три маршрута

- `GET /v1/leads/{id}/status-history`: история участия лида в кампании, право `leads:read`.
- `GET /v1/campaigns/{id}/status-history`: история кампании, право `campaigns:read`.
- `GET /v1/campaigns/{id}/accounts/{account_id}/status-history`: история аккаунта в контексте выбранной кампании, право `accounts:read`.

История аккаунта не раскрывает его работу в других кампаниях. Действует охват ключа по пространствам и кампаниям. Объект вне охвата дает 404, как несуществующий.

```bash
curl -G https://api.melioralab.io/v1/leads/5a7c3e92-1f4b-4d68-9c2e-7b0a6d4f8e31/status-history \
  -H "Authorization: Bearer $MELIORA_API_KEY" \
  -d limit=50
```

Каждый маршрут принимает `limit` и `cursor`. По умолчанию 50 записей, максимум 100. Переходы идут по возрастанию `entity_revision`, а не по времени доставки уведомления. Курсор живет 15 минут; при 410 начните новый обход и объедините записи по `id`. Подробные ответы есть в [справочнике истории](https://docs.melioralab.io/reference/status-history/).

## Запись перехода

Каждый элемент `data` имеет `object=status_transition` и содержит:

- `id`: идентификатор перехода; `entity_kind`: `lead`, `campaign` или `account`; `entity_id`: идентификатор этого объекта.
- `workspace_id`, `campaign_id`, `lead_id`: контекст. В истории кампании и аккаунта `lead_id` может быть `null`.
- `entity_revision`: порядковый номер перехода для объекта, начиная с 1. Используйте его для порядка внутри истории одного объекта.
- `from_status`, `to_status`: предыдущий и новый публичные статусы.
- `occurred_at`: время изменения; `recorded_at`: когда оно было сохранено.
- `reason_code`: `operator_action`, `schedule`, `queue_exhausted`, `recipient_not_found`, `telegram_auth`, `subscription`, `recovery` или `unspecified`.
- `source`: кто изменил статус: `user` (пользователь кабинета), `system` (автоматика сервиса), `support` (поддержка Meliora) или `unknown`. Это справка, а не инструкция клиенту.

Если причина не установлена, приходит `unspecified`, если источник неизвестен, приходит `unknown`. Сохранение того же статуса не является новым переходом. История описывает изменение поля статуса, а не каждое действие над объектом.

## Публичные статусы

У лида: `new`, `contacted`, `completed`, `replied`, `blocked`, `failed`, `suspended`, `deleted`, `opted_out`, `unknown`. Их смысл описан в [статусах лида](https://docs.melioralab.io/lead-states/#status).

У кампании: `draft`, `scheduled`, `active`, `paused`, `stopped`, `completed`, `archived`, `launching`, `failed`, `paused_no_credits`, `unknown`. См. [статусы кампании](https://docs.melioralab.io/lead-states/#campaign-status).

У аккаунта в истории:

- `online`: подключен; `offline`: отключен.
- `limited`: ограничен; `banned`: заблокирован.
- `deleted`: удален; `locked`: доступ заблокирован; `unauthorized`: требуется авторизация.
- `paused`: на паузе; `unknown`: значение не удалось определить.

Неизвестное исходное значение становится `unknown`. Оно допустимо и в `from_status`, и в `to_status`; не превращайте его в `failed` или `offline`. Набор истории аккаунта включает `paused`; в обычном списке аккаунтов это значение может быть представлено как `unknown`.

Статусы могут возвращаться к прежним значениям: например, `paused` сменяется на `active`. Для истории не подходит правило «разрешать статусам двигаться только вперед».

## Начальный снимок и полнота

`meta.baseline` содержит отдельный объект `status_baseline` с `status`, `entity_revision`, `recorded_at`, контекстом объекта и `provenance=baseline`, либо `null`. Ревизия снимка может быть 0. Это наблюдавшийся начальный статус, а не переход из выдуманного предыдущего значения. Он не создает `*.status_changed`.

Границы истории находятся в `meta`:

- `history_started_at`: начало ведения истории. Более ранние изменения не восстанавливаются.
- `available_from`: начало доступной истории.
- `retained_from`: начало сохраненного периода.
- `observed_at`: время чтения данных сервером.

Неизвестные границы равны `null`. Удаление старых записей по сроку хранения не должно выглядеть как полная история с момента создания объекта.

`meta.completeness.status` принимает `complete`, `partial` или `unknown`. Также есть `gaps`, `gaps_truncated` и `incomplete_from`. Каждый разрыв содержит `id`, `from`, `to`, `state`; состояния: `open`, `recovering`, `recovered`, `unrecoverable`, `unknown`. Список ограничен 50 интервалами, `gaps_truncated=true` сообщает о сокращении. `incomplete_from` помогает заметить более раннюю неполноту; `null` сам по себе не доказывает отсутствие разрывов.

`complete` относится к доступному периоду истории, а не ко всей жизни объекта. При `partial` или `unknown` сохраните отметку неполноты, сверяйте текущую карточку и позже повторяйте чтение истории. `has_more=false` говорит только о конце страниц.

## События смены статуса

Лента поддерживает `lead.status_changed`, `campaign.status_changed`, `account.status_changed`. Выберите [каталог `2b`](https://docs.melioralab.io/events-polling/#catalog-2b) или один конкретный новый `type`.

В `data` есть `organization_id`, `workspace`, `campaign`, `transition_id`, `entity_kind`, `entity_id`, `from_status`, `to_status`, `reason_code`, `source`, `occurred_at`, `recorded_at`. `transition_id` совпадает с `id` перехода в истории. Событие аккаунта относится к одной кампании; список других кампаний не передается.

`lead.status_changed` сообщает только о смене статуса. `lead.replied` сообщает о засчитанном бизнес-ответе: один ответивший лид учитывается один раз в кампании. Не увеличивайте счетчик ответов по `lead.status_changed` или по каждому `message.received`: последнее означает отдельное входящее сообщение. Один и тот же ответ может привести к нескольким разным типам событий об одном взаимодействии.

Повторные доставки убирайте по `event.id`. Уведомления могут прийти позже самого изменения. Для восстановления порядка прочитайте историю по `entity_revision` и сопоставьте `transition_id`; для текущего состояния сверяйте карточку. Не выбирайте итоговый статус только по порядку прихода вебхуков.

[Новые вебхуки](https://docs.melioralab.io/webhooks/#new-event-types) этих типов содержат только метаданные. Текст сообщения к изменению статуса не прилагается.
