PD Документация ← На главную

Сценарии

Сценарии — это визуальные конвейеры автоматизации, определяющие, как и когда отправляются уведомления. Создавайте их в редакторе Приложения → Сценарии — свободном холсте с узлами.

Типы узлов

Триггер (Trigger)

Каждый сценарий начинается с узла «Триггер». Он создаётся автоматически и не может быть удалён. Триггер срабатывает при вызове triggerWorkflow через GraphQL или POST /api/v1/workflows/:id/trigger через REST.

Отправка (Send)

Отправляет уведомление через настроенный канал.

ПараметрОписание
КаналPush (APNs, FCM, Web Push — без канала) или один из каналов приложения: Email, SMS, Telegram, MAX, In-App
ШаблонШаблон выбранного типа канала; тема и текст подставляют payload запуска, ключи metadata контакта и поля контакта ({{ name }}, {{ email }}, {{ locale }}) — при совпадении имён побеждает payload; явно: {{ contact.email }}, {{ contact.metadata.plan }}
ПолучательВсегда контакт, запустивший сценарий: его устройства для push, email / phone / telegramChatId / maxUserId для каналов (Telegram-шаг уходит в чат канала, если контакт не подключил бота)
КатегорияНеобязательно: контакты, отключившие категорию для этого канала, пропускаются

Задержка (Delay)

Приостанавливает выполнение на заданный период перед переходом к следующему узлу.

ПараметрОписание
DurationЗадержка в секундах, минутах, часах или днях

Фильтр (Filter)

Продолжает сценарий по условию на основе значения поля.

ПараметрОписание
FieldКлюч payload запуска (plan), поле контакта (locale, contact.email) или ключ metadata контакта (plan, contact.metadata.plan); без префикса ищется сначала в payload, затем в metadata и полях контакта
Operatoreq, neq, contains
ValueЗначение для сравнения
СегментВместо правила по полю: прогон продолжается, только если контакт подходит под сегмент в этот момент («Контакт в сегменте» в панели; segmentId в конфиге шага)

Если условие не выполнено, сценарий завершается без выполнения последующих узлов.

Дайджест (Digest)

Собирает запуски одного контакта, пришедшие за окно, в один — лекарство от усталости от уведомлений («12 новых комментариев» вместо двенадцати пушей). Первый запуск открывает окно и ждёт; каждый запуск за это время добавляет свой payload в окно и завершается (в его строке — слит в дайджест и ссылка на запуск, который его понёс); когда окно закрывается, первый запуск продолжается с собранными событиями.

ПараметрОписание
ОкноСколько окно открыто — от первого запуска (фиксированное) или от последнего (скользящее: каждый запуск отодвигает закрытие, но не дальше трёх окон от первого)
Закрыть раньше приЧисло запусков, при котором окно закрывается сразу (1–1000, по умолчанию 100)
Группировать по ключу payloadНеобязательно: поле payload триггера — отдельное окно на каждое значение (заказ, тред); без него одно окно на контакт

Шаги после дайджеста видят дополнительные переменные: {{ total }} (сколько запусков), {{#each activities}} … {{/each}} (payload каждого запуска по порядку — внутри блока {{ title }} — поле текущего события, {{ this }} — само событие, {{ @number }} — его номер), {{ first }} и {{ last }}:

{{ total }} новых событий:
{{#each activities}}• {{ @number }}. {{ title }}
{{/each}}

Не чаще (Throttle)

Пропускает не больше N запусков одного контакта за окно; запуск сверх лимита останавливается как отфильтрованный с причиной. Триггер, срабатывающий на каждое нажатие, никогда не разбудит человека чаще, скажем, раза в час.

ПараметрОписание
Не большеЗапусков, которые проходят за окно (1–1000, по умолчанию 1)
ОкноДлина окна; открывается первым прошедшим запуском и сбрасывается после истечения
Группировать по ключу payloadНеобязательно: отдельный лимит на каждое значение поля payload

Ветвление (Branch)

Условие как у фильтра — правило по полю payload запуска и контакта или «контакт в сегменте», — но вместо остановки запуска оно выбирает ветку: выход да, когда условие выполнено, иначе нет. Каждый выход — своя цепочка; когда она заканчивается, запуск продолжается со шага после ветвления. Выход, к которому ничего не подключено, просто продолжает.

Разделить (Split)

Варианты с весами (от двух до пяти), по выходу на каждый: запуск попадает в один из них — детерминированно для запуска (повтор шага идёт той же веткой), а на многих запусках доли следуют весам (50 / 50 для A/B двух сообщений, 90 / 10 для осторожного раската). Раздел Запуски называет ветку каждого запуска.

Ждать событие (Wait for event)

Останавливает запуск, пока контакт не сообщит событие (API «События» или SDK, например purchase) или не истечёт таймаут (до 30 дней). Событие и его свойства попадают в данные запуска под ключом (waited по умолчанию), и следующие шаги могут подставить {{ waited.properties.sku }} или ветвиться по нему; по таймауту запуск либо продолжается (ключ null), либо останавливается как отфильтрованный — «не купил за день → напоминание» это ожидание со стоп, «напоминание, если не купил» — то же ожидание с продолжить и ветвлением.

Запрос (Fetch)

HTTP-запрос к публичному адресу (та же защита, что у вебхуков: без приватных адресов и редиректов) с подстановкой переменных запуска в URL, заголовки и тело — https://api.example.com/users/{{ externalId }}. JSON-ответ (до 64 КБ) попадает в данные запуска под ключом (fetched по умолчанию) для шаблонов и ветвлений после него. Ответ не 2xx останавливает запуск с ошибкой, если шаг не настроен продолжать — тогда под ключом лежит { status, body } для ветвления.

Запустить сценарий (Trigger workflow)

Запускает другой сценарий приложения для того же контакта, с данными этого запуска (плюс поля шага) как payload дочернего; дочерний видит _depth и _parent_execution. Вложенность — не больше трёх, сам себя сценарий запустить не может.

Построение сценария

  1. Откройте Приложения → Сценарии и нажмите Новый сценарий
  2. Перетащите узлы из левой палитры на холст
  3. Соедините узлы, протянув связь от нижнего разъёма одного узла к верхнему разъёму следующего; у ветвления и разделения по подписанному разъёму на каждый выход
  4. Кликните узел, чтобы настроить его в правой панели
  5. Нажмите Сохранить по завершении
  6. Установите статус сценария «Активен», чтобы разрешить запуск

Запуск сценария

graphql
mutation {
  triggerWorkflow(input: {
    workflowId: "019c9a99-8aad-77b4-b2b2-719f3f8e0610"
    subscriberId: "019c9359-fe1d-73bc-90fd-594d284d24f3"
    payload: {
      name: "John"
      orderId: "ORD-001"
    }
    # Необязательно: повторный запуск с тем же ключом вернёт уже начатый
    # прогон вместо повторного выполнения сценария.
    idempotencyKey: "order-ORD-001-confirmation"
  }) {
    id
    status
    startedAt
  }
}

Из вашего бэкенда то же самое одним REST-вызовом (контакт — по вашему external_id или по PushData-id; ответ 202):

bash
curl -X POST https://api.pushdata.ru/api/v1/workflows/WORKFLOW_ID/trigger \
  -H "Authorization: ApiKey pd_ВАШ_СЕКРЕТНЫЙ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{"contact_external_id":"user-123","payload":{"name":"Иван","orderId":"ORD-001"},"idempotency_key":"order-ORD-001-confirmation"}'
json
{ "execution_id": "0192…", "workflow_id": "019c…", "status": "pending", "started_at": "2026-09-14T12:00:00.000Z" }

Событийные триггеры

Сценарий запускается и сам, когда приложение или бэкенд присылает пользовательское событие с именем, равным идентификатору триггера сценария (POST /api/v1/track/events, см. Контакты → Пользовательские события). Назовите триггер сценария order_placed, активируйте его — и каждое событие order_placed запускает прогон для этого контакта со свойствами события в payload (плюс event и occurred_at):

bash
curl -X POST https://api.pushdata.ru/api/v1/track/events \
  -H "Authorization: ApiKey pd_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id":"user-123","event":"order_placed","properties":{"orderId":"ORD-001","total":1290},"idempotency_key":"order-ORD-001"}'

Контакт — тот, у кого такой user_id (незнакомый создаётся), так что шаги SEND находят получателя как обычно; idempotency_key события становится ключом прогона, и повторная отправка не запускает второй. Клиентские SDK присылают события с публичным ключом (client.events.track(...)) — так «брошенная корзина» или «новый уровень» запускаются прямо из приложения. Событие без активного сценария с таким именем только сохраняется — для сегментов.

Триггеры по сегменту

Сценарий может запускаться, когда контакт попадает в сегмент — выберите «Контакт попал в сегмент» при создании (идентификатор триггера станет segment:<id сегмента>). Каждый контакт, который начинает подходить под правила сегмента, запускает прогон — один раз на вход; те, кто уже внутри при активации, записываются молча. Детали и тайминги: Контакты → «Вход в сегмент» как триггер.

Правила

  • Сценарий должен быть Активен, чтобы его можно было запустить (иначе 409 workflow_inactive)
  • Если у какого-либо шага SEND нет жёстко заданного получателя, subscriberId обязателен
  • Объект payload доступен внутри шаблонов как {{ variable }}; это должен быть JSON-объект не больше 64 КБ (иначе 400)
  • idempotencyKey (≤ 200 символов, уникален в пределах сценария) делает запуск безопасным для повторов: тот же ключ возвращает существующий прогон
  • Подписчик должен быть контактом приложения сценария

Порядок выполнения

Шаги выполняются в порядке цепочки, нарисованной на холсте (по связям, а не по визуальному расположению). Не прошедший FILTER — или THROTTLE сверх лимита — завершает прогон со статусом filtered; DIGEST сливает прогоны окна в первый. BRANCH и SPLIT открывают ветки: прогон идёт по одному из выходов узла и, когда та цепочка заканчивается, продолжается со шага после узла; вложенность веток — до трёх.

В API дерево — плоский список: у каждого шага есть order (уникальный в сценарии) и path — пустой для основной цепочки, <order>.then / <order>.else для веток BRANCH с этим order, <order>.<ключ варианта> под SPLIT, вложенно 3.then.7.a. Шаги одного path идут по order; прогон начинается с первого шага основной цепочки.

json
{
  "steps": [
    { "type": "BRANCH", "order": 0, "config": { "field": "plan", "operator": "eq", "value": "pro" } },
    { "type": "SEND", "order": 1, "path": "0.then", "config": { "channelType": "PUSH", "templateId": "<id>" } },
    { "type": "SEND", "order": 2, "path": "0.else", "config": { "channelType": "EMAIL", "channelId": "<id>", "templateId": "<id>" } },
    { "type": "SPLIT", "order": 3, "config": { "variants": [{ "key": "a", "weight": 50 }, { "key": "b", "weight": 50 }] } },
    { "type": "SEND", "order": 4, "path": "3.a", "config": { "channelType": "PUSH", "templateId": "<id>" } },
    { "type": "SEND", "order": 5, "path": "3.b", "config": { "channelType": "PUSH", "templateId": "<id>" } },
    { "type": "WAIT_FOR_EVENT", "order": 6, "config": { "event": "purchase", "timeoutMs": 86400000, "onTimeout": "stop" } },
    { "type": "FETCH", "order": 7, "config": { "url": "https://api.example.com/orders/{{ waited.properties.order }}", "saveAs": "order" } },
    { "type": "TRIGGER_WORKFLOW", "order": 8, "config": { "workflowId": "<id>" } }
  ]
}

WorkflowExecution.branchChoices хранит выбор каждого прогона ({ "0": "then", "3": "b" }). Прогон запускается через triggerWorkflow (API или дашборд) или пользовательским событием с именем триггера; cron-триггеров нет. Используйте раздел Запуски для отслеживания истории выполнения.