Workflow-мониторы (multi-step API)
Обычный HTTP-монитор дёргает один URL. Но реальная проверка живости API часто требует последовательности: сначала залогиниться, получить токен, потом дёрнуть защищённый endpoint с этим токеном. Workflow-монитор выполняет именно такую цепочку — до 20 HTTP-шагов подряд, передавая значения из ответа одного шага в запросы следующих.
Шаги выполняются строго по порядку. Если любой шаг не прошёл (timeout,
неверный HTTP-статус, тело не содержит ожидаемого, JSONPath-assert не совпал или
extractor не нашёл значение) — цепочка останавливается, монитор переходит в
статус down и приходит alert с указанием упавшего шага.
Создание в админке
Заголовок раздела «Создание в админке»app.notifly.ru → Мониторы → Создать → «Что вы хотите проверять?» → «Сценарий из нескольких шагов» → «HTTP-запросы (API)». Готовые мониторы живут на вкладке Workflow.
В диалоге шаги можно заполнить вручную, собрать ИИ-помощником по описанию (кнопка «Подобрать шаг», см. ниже) или начать «Из шаблона…»:
| Шаблон | Шаги |
|---|---|
| Проверка REST API с авторизацией | GET /health → POST /login (извлечь token) → GET /me с Bearer |
| Проверка формы логина | GET /login (тело содержит <form) → POST /login с учётными данными |
| Цепочка с JSONPath-извлечением | список → детальный endpoint по извлечённому id |
Шаблон только предзаполняет форму: замените URL и данные на свои. Кнопка «Тестовый прогон» выполняет всю цепочку без сохранения (см. Тестовый прогон).
Как устроен шаг
Заголовок раздела «Как устроен шаг»Каждый шаг (WorkflowStep) — это один HTTP-запрос со своими проверками и
извлекаемыми переменными:
| Поле | Тип | Назначение |
|---|---|---|
name | string | человеко-читаемое имя шага (попадёт в alert) — обязательно |
method | string | GET / POST / PUT / PATCH / DELETE / HEAD — обязательно |
url | string | URL запроса; поддерживает {{var}} — обязательно |
headers | string | JSON-объект {"Header":"Value"}; значения поддерживают {{var}} |
body | string | тело запроса; поддерживает {{var}} |
expectedStatus | int | 0 = любой 2xx; иначе точный статус в [100, 599] |
bodyContains | string | подстрока, которая должна присутствовать в теле ответа |
assertJsonPath | string | JSONPath для проверки значения в теле (см. ниже) |
assertValue | string | ожидаемое значение для assertJsonPath (обязательно, если задан assertJsonPath) |
extractors | array | список переменных, извлекаемых из ответа этого шага |
Сами шаги хранятся в поле steps монитора как JSON-массив, сериализованный в
строку. Метод при сохранении приводится к верхнему регистру.
Передача переменных между шагами
Заголовок раздела «Передача переменных между шагами»Каждый extractor — это пара {name, jsonPath}:
name— имя переменной, под которым результат станет доступен в следующих шагах;jsonPath— путь к значению в JSON-ответе.
Извлечённое значение подставляется в url, headers и body последующих шагов
по синтаксису {{name}}. Неизвестные плейсхолдеры остаются как есть.
JSONPath — простой: $.token, $.user.id, индексы массива через точку —
$.items.0.id. Корень $ опционален. Скобочная запись ($.items[0].id),
фильтры и * не поддерживаются.
Пример: логин → токен → защищённый endpoint
Заголовок раздела «Пример: логин → токен → защищённый endpoint»[ { "name": "Login", "method": "POST", "url": "https://api.example.com/auth/login", "headers": "{\"Content-Type\":\"application/json\"}", "body": "{\"email\":\"bot@example.com\",\"password\":\"s3cret\"}", "expectedStatus": 200, "extractors": [ {"name": "token", "jsonPath": "$.access_token"}, {"name": "userId", "jsonPath": "$.user.id"} ] }, { "name": "Профиль пользователя", "method": "GET", "url": "https://api.example.com/users/{{userId}}", "headers": "{\"Authorization\":\"Bearer {{token}}\"}", "expectedStatus": 200, "assertJsonPath": "$.status", "assertValue": "active" }]Первый шаг логинится и извлекает token и userId. Второй подставляет оба в URL
и заголовок Authorization, ждёт 200 и проверяет, что $.status == "active".
Параметры монитора
Заголовок раздела «Параметры монитора»| Поле | По умолчанию | Ограничения |
|---|---|---|
appid | — | канал, в который уйдёт alert — обязательно |
name | — | название монитора, 1..200 символов — обязательно |
steps | — | JSON-массив шагов (строкой): 1..20 штук — обязательно |
intervalSec | — | как часто проверять, 60..86400 сек — обязательно |
timeoutSec | 15 | timeout на один шаг, максимум 60 сек |
alertMessage | — | текст уведомления, 1..2000 символов — обязательно |
alertTitle | пусто | заголовок уведомления |
alertMessageMarkdown | false | трактовать alertMessage как Markdown |
alertPriority | 0 | приоритет уведомления, 0..10 |
notifyOnChange | false | слать уведомление, когда любое извлечённое значение изменилось с прошлого успешного прогона |
Канал должен быть вашим или расшаренным вам с правом отправки.
При падении приходит сообщение с заголовком alertTitle (пустой — «Workflow
«‹название›» failed») и текстом alertMessage, к которому дописаны упавший шаг
и причина:
Шаг: #2 Профиль пользователяОшибка: HTTP 401 (expected 200)- Алерт уходит при переходе в
downи ещё раз — если цепочка начала падать на другом шаге. Пока падает тот же шаг, повторных алертов нет: отметка отправленного алерта хранится в поле монитораalertedAt. - Re-arm: если изменить проверочные параметры (
steps,intervalSec,timeoutSec,notifyOnChange) черезPUT, отметкаalertedAtсбрасывается и проверка перепланируется «на сейчас» — если цепочка всё ещё падает, придёт свежий алерт. Правка названия или текстов алерта ничего не перезапускает. - Отдельного уведомления о восстановлении workflow-мониторы не шлют: при
успешном прогоне монитор просто возвращается в
up. - В окне обслуживания прогоны идут и пишутся в
историю, но алерт о падении откладывается:
alertedAtне ставится, и если после окна цепочка всё ещё падает, первая же проверка пришлёт алерт. Уведомления on-change в окне не отправляются.
Алерт — обычное сообщение канала: его досылка во внешние каналы подчиняется
тихим часам (высокий alertPriority пробивает тишину).
Если монитор добавлен на статус-страницу, переходы
up↔down открывают и закрывают на ней авто-инцидент.
Режим on-change
Заголовок раздела «Режим on-change»При notifyOnChange: true монитор запоминает значения всех extractor-ов
последнего успешного прогона и шлёт уведомление, когда что-то из них
изменилось. В тексте — строки вида token: старое → новое; заголовок по
умолчанию — «Workflow «‹название›»: данные изменились». Первое наблюдение
значения уведомления не даёт, а при падении базовые значения сохраняются. Удобно
следить не только за доступностью, но и за тем, что какое-то поле в ответе API
«поехало» (например, версия билда, цена, остаток на складе).
ИИ-сборка шага (build-step)
Заголовок раздела «ИИ-сборка шага (build-step)»Чтобы не описывать HTTP-запрос руками, есть POST /workflow-monitor/build-step:
вы пишете, что должен делать шаг, на естественном языке — LLM подбирает метод,
URL, заголовки, тело, проверки и extractors, после чего кандидат реально
выполняется для верификации.
Ранее подтверждённые шаги передаются в steps (не больше 20) — они
воспроизводятся, чтобы накопить переменные и дать модели пример ответа
предыдущего шага (это помогает ей выбрать правильный JSONPath).
curl -X POST "$NOTIFLY_URL/workflow-monitor/build-step" \ -H "X-Notifly-Key: <api-token>" \ -H "Content-Type: application/json" \ -d '{ "description": "получить профиль текущего пользователя с Bearer-токеном из прошлого шага", "steps": [ /* уже подтверждённые шаги */ ], "timeoutSec": 15 }'В ответе:
| Поле | Назначение |
|---|---|
step | предложенный WorkflowStep (метод, URL, заголовки, тело, проверки, extractors) |
label | короткое имя шага |
reason | пояснение, почему модель выбрала такой запрос |
verified | true, если кандидат удалось выполнить успешно |
statusCode | HTTP-статус ответа кандидата |
sampleBody | фрагмент тела ответа (до 400 символов) |
extractedVars | переменные, реально извлечённые этим шагом |
availableVars | переменные, доступные на этом шаге (из предыдущих) |
note | заполняется, если верификация не удалась — с текстом ошибки |
Тестовый прогон (test)
Заголовок раздела «Тестовый прогон (test)»Перед сохранением монитора прогоните всю цепочку через POST /workflow-monitor/test:
curl -X POST "$NOTIFLY_URL/workflow-monitor/test" \ -H "X-Notifly-Key: <api-token>" \ -H "Content-Type: application/json" \ -d '{"steps": [ /* массив шагов */ ], "timeoutSec": 15}'Здесь steps — обычный JSON-массив (не строка), 1..20 шагов; timeoutSec —
на шаг, по умолчанию 15, больше 60 урезается до 60. Ответ:
{"ok": true, "failedStep": 0, "vars": {"token": "ey...", "userId": "42"}}При успехе ok: true и vars — итоговый набор накопленных переменных. При сбое:
{"ok": false, "failedStep": 1, "error": "HTTP 401 (expected 200)"}failedStep — индекс упавшего шага (с нуля; имеет смысл только при
ok: false), error — причина: неверный статус, отсутствие подстроки/JSONPath,
несовпадение assert-значения, сетевая ошибка или timeout.
Пауза, история, квота
Заголовок раздела «Пауза, история, квота»POST /workflow-monitor/:id/pause ставит статус paused и останавливает
проверки, …/resume возвращает pending и ставит монитор в очередь на проверку
немедленно; оба отвечают объектом монитора. Изменение шагов, интервала,
timeout-а или notifyOnChange тоже перепланирует проверку на «сейчас».
Вкладка История монитора показывает прогоны и график средней длительности
каждого шага со сбоями по шагам; через API — GET /monitor-history/workflow_monitor/:id.
При падении в самом мониторе видны lastError и lastFailedStep.
Каждый прогон цепочки — одно событие дневной квоты dailyEvents, независимо
от числа шагов. Если квота исчерпана, проверки откладываются до 00:05 МСК
следующего дня — см. Квоты и тарифы.
REST API
Заголовок раздела «REST API»| Метод и путь | Права API-токена | Назначение |
|---|---|---|
GET /workflow-monitor | read | список мониторов |
POST /workflow-monitor | write | создать монитор |
PUT /workflow-monitor/:id | write | обновить |
DELETE /workflow-monitor/:id | write | удалить |
POST /workflow-monitor/:id/pause | write | приостановить проверки |
POST /workflow-monitor/:id/resume | write | возобновить проверки |
POST /workflow-monitor/build-step | write | ИИ-подбор и верификация одного шага |
POST /workflow-monitor/test | write | прогнать цепочку без сохранения |
Авторизация — заголовок X-Notifly-Key с API-токеном (M…):
чтение — любым токеном, изменения — токеном с доступом write (иначе 403).
Токен, ограниченный по каналам, видит и меняет только мониторы своих каналов.
Те же операции есть в Go/Python SDK и MCP-сервере.