Workflow-мониторы (multi-step API)
Обычный HTTP-монитор дёргает один URL. Но реальная проверка живости API часто требует последовательности: сначала залогиниться, получить токен, потом дёрнуть защищённый endpoint с этим токеном. Workflow-монитор выполняет именно такую цепочку — до 20 HTTP-шагов подряд, передавая значения из ответа одного шага в запросы следующих.
Шаги выполняются строго по порядку. Если любой шаг не прошёл (timeout,
неверный HTTP-статус, тело не содержит ожидаемого, JSONPath-assert не совпал или
extractor не нашёл значение) — цепочка останавливается, монитор переходит в
статус down и приходит alert с указанием упавшего шага.
Как устроен шаг
Заголовок раздела «Как устроен шаг»Каждый шаг (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. Корень $ опционален.
Пример: логин → токен → защищённый 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 | слать уведомление, когда любое извлечённое значение изменилось с прошлого успешного прогона |
Режим on-change
Заголовок раздела «Режим on-change»При notifyOnChange: true монитор запоминает последние извлечённые значения
(extractors) и шлёт уведомление, когда что-то из них изменилось. Удобно следить
не только за доступностью, но и за тем, что какое-то поле в ответе API «поехало»
(например, версия билда, цена, остаток на складе).
ИИ-сборка шага (build-step)
Заголовок раздела «ИИ-сборка шага (build-step)»Чтобы не описывать HTTP-запрос руками, есть POST /workflow-monitor/build-step:
вы пишете, что должен делать шаг, на естественном языке — LLM подбирает метод,
URL, заголовки, тело, проверки и extractors, после чего кандидат реально
выполняется для верификации.
Ранее подтверждённые шаги передаются в steps — они воспроизводятся, чтобы
накопить переменные и дать модели пример ответа предыдущего шага (это помогает ей
выбрать правильный JSONPath).
curl -X POST "$NOTIFLY_URL/workflow-monitor/build-step" \ -H "X-Notifly-Key: C-xxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "description": "получить профиль текущего пользователя с Bearer-токеном из прошлого шага", "steps": [ /* уже подтверждённые шаги */ ], "timeoutSec": 15 }'В ответе:
| Поле | Назначение |
|---|---|
step | предложенный WorkflowStep (метод, URL, заголовки, тело, проверки, extractors) |
label | короткое имя шага |
reason | пояснение, почему модель выбрала такой запрос |
verified | true, если кандидат удалось выполнить успешно |
statusCode | HTTP-статус ответа кандидата |
sampleBody | фрагмент тела ответа |
extractedVars | переменные, реально извлечённые этим шагом |
availableVars | переменные, доступные на этом шаге (из предыдущих) |
note | заполняется, если верификация не удалась — с текстом ошибки |
Тестовый прогон (test)
Заголовок раздела «Тестовый прогон (test)»Перед сохранением монитора прогоните всю цепочку через POST /workflow-monitor/test:
curl -X POST "$NOTIFLY_URL/workflow-monitor/test" \ -H "X-Notifly-Key: C-xxxxxxxx" \ -H "Content-Type: application/json" \ -d '{"steps": [ /* массив шагов */ ], "timeoutSec": 15}'Ответ:
{ "ok": true, "vars": {"token": "ey...", "userId": "42"} }При успехе ok: true и vars — итоговый набор накопленных переменных. При сбое:
{ "ok": false, "failedStep": 1, "error": "HTTP 401 (expected 200)" }failedStep — индекс упавшего шага (с нуля), error — причина: неверный статус,
отсутствие подстроки/JSONPath, несовпадение assert-значения или сетевой timeout.
Пауза и возобновление
Заголовок раздела «Пауза и возобновление»POST /workflow-monitor/:id/pause останавливает проверки (следующая проверка
отодвигается далеко в будущее), …/resume — ставит монитор в очередь на проверку
немедленно. Косметическое редактирование (название, текст алерта) не перепланирует
проверку; изменение шагов, интервала, timeout-а или notifyOnChange — перепланирует
на «сейчас».
REST API
Заголовок раздела «REST API»| Метод и путь | Авторизация | Назначение |
|---|---|---|
GET /workflow-monitor | client-token | список мониторов |
POST /workflow-monitor | client-token (write) | создать монитор |
PUT /workflow-monitor/:id | client-token (write) | обновить |
DELETE /workflow-monitor/:id | client-token (write) | удалить |
POST /workflow-monitor/:id/pause | client-token (write) | приостановить проверки |
POST /workflow-monitor/:id/resume | client-token (write) | возобновить проверки |
POST /workflow-monitor/build-step | client-token (write) | ИИ-подбор и верификация одного шага |
POST /workflow-monitor/test | client-token (write) | прогнать цепочку без сохранения |
Все endpoint-ы доступны и под MCP-кодом (M…): чтение — любым MCP-кодом,
запись — кодом со scope write. Управлять мониторами можно и через
ассистента, и из админки.