Кампании
Кампания – это многошаговый автоматический путь подписчика: вход по триггеру, затем последовательность узлов (сообщения, задержки, условия, эксперименты), которая может растягиваться на дни и недели. Это не то же самое, что рассылка или email-рассылка – у тех один документ контента и одна волна отправки; кампания же – это граф с ветвлениями, который читает и меняет данные подписчика на каждом шаге.
Версии и черновик
У кампании в любой момент ровно один редактируемый черновик (draft) и,
если она хоть раз публиковалась, история immutable-версий: draft →
published → retired. Черновик содержит триггер, аудиторию, настройки и
граф узлов. Правка черновика идёт через PUT /draft с expected_revision:
если кто-то другой уже сохранил черновик, запрос отклоняется как конфликт, а
не тихо перезатирает чужую правку.
Публикация (POST /publish) замораживает текущий черновик как новую
опубликованную версию и сразу открывает следующий черновик – его копию.
Подписчик, вошедший в кампанию во время действия версии N, доходит по её
пути до конца на версии N, даже если позже опубликуют версию N+1: триггер,
аудиторию, настройки и граф уже вошедшего путешествия версия N+1 не меняет.
Изменить граф узлов можно только когда кампания остановлена – при статусе «Выполняется» или «На паузе» сохранение графа отклоняется с ошибкой: кто-то может стоять именно на этом узле по его идентификатору, и менять граф под живым подписчиком нельзя.
Отдельно от версий есть клонирование: из любой версии – черновика, опубликованной или архивной – можно открыть новый черновик с её содержимым, заменив текущий черновик. Так же можно архивировать кампанию (убрать из активного списка без удаления истории) – но только когда она остановлена.
Триггеры входа
- Вручную – без настроек; кнопка «Отправить тест себе» в редакторе вызывает тот же путь и сразу выполняет входной узел, не дожидаясь фонового обхода.
- Событие сайта – то же событие клиентского SDK/виджета, что и в реакциях, с тем же редактором условий.
- По расписанию – один раз в момент
atлибо повторяясь. Повторяющееся расписание задаёт локальное время суток (ЧЧ:MM) в явном IANA-часовом поясе – значение «Local» не принимается – опционально фильтр по дням недели и обязательныеstart_at/end_atне длиннее двух лет: у повторяющегося расписания обязательно есть конец, иначе забытая кампания сканировала бы аудиторию вечно. Момента, которого не существует из-за перевода часов весной, по умолчанию просто нет в расписании; политика «следующий существующий момент» переносит его на конец провала вместо пропуска. - Изменение метки – добавление или снятие одной конкретной метки, не оба сразу: это разные путешествия с разным содержанием.
- Изменение свойства – переход одобренного свойства профиля из одного состояния в другое. Условия «было» и «стало» независимы и оба необязательны; повторное сохранение того же значения переходом не считается и вход не вызывает.
- Вход в сегмент – переход участия в готовом сегменте из «не входит» в «входит». Обычный пересчёт, который лишь подтверждает уже имеющееся участие, входом не считается.
Узлы графа
Граф – это узлы и рёбра между ними; у рёбра есть метка ветки (например, yes/
no). Ровно один узел без входящих рёбер – точка входа; терминальные узлы
(«Цель», «Выход») не имеют исходящих рёбер, и от каждого узла должен быть путь
хотя бы до одного терминального узла – граф с недостижимым узлом или узлом без
выхода к финалу не сохранится. У узла может быть максимум 32 КиБ конфигурации;
у кампании в целом – не больше 200 узлов и 400 рёбер.
- Сообщение – блоки текста/фото/файла/задержки, выполняются как обычная реакция тому же подписчику. Блоки ИИ, вложенная реакция, «ожидаемый ответ» и сохранение параметров с побочным эффектом здесь не поддерживаются – повторный запуск узла после сбоя должен быть безопасным.
- Контент – в отличие от «Сообщения», отправляет конкретную опубликованную и зафиксированную по версии документ на явно названный канал (Telegram, VK, WhatsApp или веб-чат) и никогда не переключается на другой канал сам: недоступность адресата либо уходит по отдельной ветке «когда канал недоступен», если она проведена, либо узел явно проваливается.
- Задержка – ждёт заданное число секунд (не больше 180 дней).
- Ожидание события – ждёт клиентское событие по имени (до 64 символов, без
зарезервированного префикса
$) с таймаутом до 180 дней; у узла ровно две ветки – основная (событие пришло) иtimeout. - Условие – ветвится
yes/noпо параметрам подписчика, периодам времени, давности последнего визита или числу сообщений – тот же словарь условий, что у реакций. - Разделение – весовое A/B-ветвление: подписчик детерминированно попадает в одну и ту же ветку по хэшу узла и своего идентификатора, и это не меняется при повторной проверке или перезапуске.
- Эксперимент – ветвится по варианту общего эксперимента с закреплёнными идентификатором и версией; от двух до шестнадцати вариантов, и каждый объявленный вариант – обязательная ветка: невыведенный вариант молча обрывал бы путешествие тем, кому эксперимент его назначил.
- Доступность канала – ветвится
yes/noпо тому, можно ли именно сейчас достучаться до подписчика на явно названном канале (email и телефон не подходят – это не канал доставки). Существует, чтобы автор явно решал вопрос резервного канала, а не полагался на то, что отправка сама переключится. - Действие – смена меток; снятие параметров (установка, добавление и
инкремент здесь не поддерживаются – тот же принцип безопасного повтора, что
у «Сообщения»); синхронный веб-запрос (без фонового режима, без вложенных
реакций на успех/ошибку, заголовок
Idempotency-Keyзарезервирован); синхронизация с подключённой CRM; назначение диалога поддержки агенту или группе; отправка клиентского события (как вызовtrack()из виджета – увидят сегменты, воронки и подходящий триггер); запуск lead-бота. - Цель и Выход – терминальные узлы без настроек: первый – успешное завершение, второй – уход без успеха.
Предпроверка и публикация
POST /preflight проверяет форму текущего черновика (тот же граф-валидатор,
что и при каждом сохранении) и связи с другими сущностями – существуют ли
названные сегменты, документы контента, эксперименты – и ничего не отправляет.
Ответ – ready, номер версии, её контрольная сумма и список ошибок с кодом
(invalid_graph, invalid_reference) и текстом. Предпроверка не считает
размер аудитории, доступность каналов или согласия – это не входит в её
задачу.
POST /publish перепроверяет те же связи заново и в одной транзакции: клиент,
который пропустил предпроверку или у которого мир успел измениться, не
опубликует кампанию со ссылкой на удалённый сегмент или документ. Публикация
требует текущей ревизии черновика – устаревшая ревизия или уже
опубликованный черновик отвечают конфликтом без частичного результата.
Отчёт по версии и трейс путешествия
Отчёт (GET /report) считается по одной версии, а не по кампании в целом:
у версии N и версии N+1 разные счётчики, публикация новой версии не сдвигает
цифры старой. В отчёте – воронка путешествий (вошли, активны, ждут, на
повторной попытке, дошли, вышли, провалились) и по каждому узлу – вошли,
завершили, провалились. Отчёт зафиксирован (sealed), когда версия уже не
принимает новых вошедших и ни одно путешествие по ней не может сдвинуться –
такие цифры сохранены как есть и больше не пересчитываются; отчёт живой
опубликованной версии всегда пересчитывается заново.
Трейс одного путешествия (GET /journeys/{subscriberID}/{runNo}) – это
ограниченный по числу событий журнал: вход в узел, сработавший эффект, уход в
ожидание, выход из ожидания, назначенная повторная попытка, отказ после
исчерпания попыток, завершение. В трейсе – идентификаторы, ветки, номера
попыток и коды ошибок, но никогда текст сообщения или ответ провайдера: это
аудит пройденного пути, а не копия того, что было отправлено. Флаг
truncated показывает, что путешествие превысило лимит событий и часть
записей не сохранилась. Отдельный список (GET /failures) показывает, кто
застрял и на каком узле, после того как раннер исчерпал попытки; застрявшее
путешествие можно перезапустить (POST /journeys/{subscriberID}/{runNo}/retry).
Тихие часы
У версии есть свободные настройки (settings), которые по умолчанию создаются
как {"allow_reentry": false, "timezone_mode": "bot", "quiet_hours": {"enabled": false}}.
Повторный вход (allow_reentry) в кампании – это
отдельное, реально работающее поле самой кампании (не настроек версии): оно
решает, может ли один подписчик войти в кампанию повторно. А вот
timezone_mode и quiet_hours внутри settings на сегодня – это только
зарезервированная форма конфигурации: раннер кампаний их не читает и не
применяет. Это отличает их от одноимённой функции Web Push,
где тихие часы действительно откладывают доставку. Не закладывайтесь на то,
что кампания сама подождёт «удобное» время – паузу нужно моделировать узлом
«Задержка» или условием по периоду времени.
Права
Личные токены и роли видят кампании через три отдельных scope: campaigns:read,
campaigns:write и campaigns:publish – публикация версии и перезапуск
застрявшего путешествия отдельно от обычного редактирования черновика. Все
три требуют право бота «Реакции»: без него раздел кампаний не виден и не
доступен ни на чтение, ни на запись.
Что дальше
- Рассылки – разовая отправка одного документа, без графа и без версий.
- Email-рассылки – похожий разовый сценарий для почты.
- Эксперименты и атрибуция – общий эксперимент, на который может ссылаться узел «Эксперимент».
- Люди (CRM) – сегменты и метки для аудитории и триггеров.
- Студия контента – документы для узла «Контент».
- REST API и токены – маршруты кампаний и их scope.