История статусов
История хранит фактические изменения статуса. Она помогает восстановить порядок изменений, а не только узнать текущее значение.
Новые возможности включаются для кабинета по запросу.
#Три маршрута
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, как несуществующий.
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. Подробные ответы есть в справочнике истории.
#Запись перехода
Каждый элемент 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. Их смысл описан в статусах лида.
У кампании: draft, scheduled, active, paused, stopped, completed, archived, launching, failed, paused_no_credits, unknown. См. статусы кампании.
У аккаунта в истории:
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 или один конкретный новый 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; для текущего состояния сверяйте карточку. Не выбирайте итоговый статус только по порядку прихода вебхуков.
Новые вебхуки этих типов содержат только метаданные. Текст сообщения к изменению статуса не прилагается.