Перейти к содержимому

Документация REST API

Notifly предоставляет REST API для управления каналами, клиентами, сообщениями, мониторингом, метриками и пользователями. Все примеры используют базовый URL API https://api.notifly.ru (можно подставить через переменную $NOTIFLY_URL). https://notifly.ru — это сайт документации, API там нет. Админка (веб-интерфейс) живёт на https://app.notifly.ru/.

Токены Notifly различаются по первой букве. Длина — 23 символа (префикс + 22).

ТипПрефиксНазначение
Ключ канала (app-токен)AОтправка в свой канал (POST /message, POST /ask, приёмники мониторинга); с правом чтения — ещё и чтение сообщений этого канала
Токен доступа к каналуSКлюч получателя делегированного доступа: то же, что A…, но отправка — только при праве send
API-токенMПрограммный доступ к аккаунту (read или read+write, скоуп по каналам), см. API-токены
Токен устройстваCСессия приложения или браузера: всё, что умеет API-токен, плюс управление устройствами, API-токенами, паролем и 2FA. Не ключ для интеграций
Ping-токен heartbeatHТолько в URL /heartbeat/ping/{token}
Токен webhook-роутераRТолько в URL /router/{token}/…

Токены web-скриптов (T…) и источников метрик (M…, но это не API-токен) тоже живут только в URL своих публичных эндпоинтов и доступа к аккаунту не дают.

Токен передаётся одним из способов (если прислано несколько, берётся первый по этому списку):

  1. заголовок X-Notifly-Key;
  2. заголовок X-Gotify-Key (устаревший, для совместимости с клиентами Gotify);
  3. заголовок Authorization: Bearer …;
  4. query-параметр ?token= — для транспортов без заголовков (WebSocket, SSE, <img>);
  5. cookie notifly-client-token — её ставит POST /auth/local/login для браузера.
Окно терминала
# 1. Заголовок X-Notifly-Key
curl -H "X-Notifly-Key: MtVOKLDNuD7HR9y7QkMecC5" https://api.notifly.ru/application
# 2. Query-параметр
curl "https://api.notifly.ru/application?token=CK2UDmhduKshCyz-RtqxiLx"
# 3. Bearer-токен
curl -H "Authorization: Bearer CK2UDmhduKshCyz-RtqxiLx" https://api.notifly.ru/application

Токены канала (A…/S… с правом чтения) принимаются и на части клиентских ручек, но видят только свой канал: GET /application вернёт один этот канал, GET /message и GET /message/search — только его сообщения. Операции уровня аккаунта (устройства, API-токены, мониторы, пользователь) им запрещены — 403.

Также поддерживается Basic Auth (логин/пароль) — но только на ручках, нужных клиенту, у которого токена ещё нет:

РучкаЗачем
POST /auth/local/loginполучить токен устройства по логину и паролю
GET /current/userпроверить пару
GET /client, GET /client/online, POST /client, POST /client/:id/reconnectзавести устройство или переподключить существующее
POST /applicationсоздать канал ради его app-токена
POST /web-script/:id/sourcemapsвыгрузка source maps из CI

На всех остальных эндпоинтах логин-пара не принимается — нужен токен. Попытки входа парой ограничены по частоте с одного адреса, а аккаунт с неподтверждённым email не пускается никуда. Аккаунт с включённой 2FA Basic-парой не пройдёт (401 second factor required) — только через POST /auth/local/login и второй шаг.

В примерах ниже $TOKEN — API-токен (M…) со страницы API-токены в админке либо токен устройства (C…) из ответа POST /auth/local/login. Там, где нужен именно токен устройства, это сказано явно.


Эндпоинты доступны без аутентификации.

Окно терминала
curl https://api.notifly.ru/health
{"health": "green", "database": "green"}

Если база недоступна — 503 с "health": "red".

Окно терминала
curl https://api.notifly.ru/version
{"version": "ya-1.0.0", "commit": "...", "buildDate": "..."}
Окно терминала
curl https://api.notifly.ru/serverinfo
{"version": "ya-1.0.0", "register": false, "oidc": false}

Логин и пароль передаются через Basic Auth. Создаёт устройство, возвращает его токен (полное значение — только в этом ответе) и ставит cookie. Необязательные поля тела: name (имя устройства) и platform.

Окно терминала
curl -u user@example.com:пароль https://api.notifly.ru/auth/local/login \
-X POST -d "name=my-cli-client"
{
"id": 1,
"name": "my-cli-client",
"token": "CK2UDmhduKshCyz-RtqxiLx",
"user_id": 1,
"platform": "web"
}

Если лимит устройств тарифа исчерпан, самое старое активное устройство приостанавливается, а в ответе появляется suspended_device_id. Если у аккаунта включена 2FA, вместо устройства приходит 401 с полем mfa — см. Двухфакторный вход.

Ротирует токен устройства и очищает cookie. Отвечает 200 даже с недействительным токеном.

Окно терминала
curl -H "X-Notifly-Key: CK2UDmhduKshCyz-RtqxiLx" \
https://api.notifly.ru/auth/logout -X POST

Для аккаунта с 2FA верный пароль на POST /auth/local/login возвращает не устройство, а 401 с challenge:

{
"error": "Unauthorized",
"errorCode": 401,
"errorDescription": "second factor required",
"mfa": {
"challenge": "…",
"methods": ["totp", "mobile", "recovery"],
"mobileCode": "47",
"expiresIn": 300
}
}

mobile предлагается, только если в профиле включено подтверждение входа с телефона. Challenge живёт 5 минут и одноразовый.

Метод и путьАутентификацияОписание
POST /auth/mfa/verifychallenge в телеВторой шаг. Тело: challenge, method (totp|recovery|mobile), code (для totp/recovery), необязательные name, platform. Успех — тот же ответ, что у логина. Неверный код — 401 invalid code, мёртвый challenge — 410
POST /auth/mfa/challengechallenge в телеПоллинг для метода mobile: {"status": "pending|approved", "mobileCode", "expiresIn"}; неизвестный challenge — 404
GET /auth/mfa/pendingтокен устройстваДля телефона: входы, ожидающие подтверждения (ip, kind, createdAt, expiresIn)
POST /auth/mfa/approveтокен устройстваДля телефона: подтвердить вход, тело {"code": "47"} (код с экрана входа). Нет совпадения — 404, устройство не подтверждающее — 403

Для метода mobile: веб показывает mobileCode, владелец вводит его в приложении (/auth/mfa/approve), веб опрашивает /auth/mfa/challenge и после approved вызывает /auth/mfa/verify с "method": "mobile".

Окно терминала
curl https://api.notifly.ru/auth/mfa/verify \
-H "Content-Type: application/json" \
-d '{"challenge": "…", "method": "totp", "code": "123456", "name": "my-cli-client"}'

Публичный эндпоинт (без авторизации). Отправляет на указанный email письмо со ссылкой для сброса пароля. Ответ всегда 200, даже если пользователя нет, — чтобы не раскрывать, какие адреса зарегистрированы.

Окно терминала
curl https://api.notifly.ru/user/reset-password \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'

POST /user/reset-password/confirm — подтвердить сброс пароля

Заголовок раздела «POST /user/reset-password/confirm — подтвердить сброс пароля»

Публичный эндпоинт. Принимает token из письма и новый пароль pass (от 8 символов, не длиннее 72 байт).

Окно терминала
curl https://api.notifly.ru/user/reset-password/confirm \
-H "Content-Type: application/json" \
-d '{"token": "<из письма>", "pass": "новый-пароль"}'

Сброс пароля — сценарий восстановления после угона, поэтому вместе с паролем аннулируются и выданные аккаунту секреты: все устройства разлогиниваются (токены ротируются, вернуть доступ можно повторным входом или через POST /client/:id/reconnect) и все API-токены удаляются — их придётся выпустить заново. Ключи каналов (A…) и токены доступа к каналам (S…) продолжают работать: они ограничены одним каналом и доступа к аккаунту не дают.

Публичный эндпоинт. Открывается по ссылке из письма-подтверждения (/user/verify?token=...) и активирует адрес пользователя.

Окно терминала
curl "https://api.notifly.ru/user/verify?token=<из письма>"

Канал (application в URL API — для совместимости с протоколом Gotify) — это источник сообщений. У каждого канала есть свой app-токен для отправки.

Свои каналы и каналы, к которым принят делегированный доступ.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/application
[
{
"id": 1,
"token": "ApNK7NiI0ltrJf3a8BNsOiD",
"name": "Мониторинг",
"description": "Оповещения от системы мониторинга",
"internal": false,
"image": "https://…/channel-logos/1/1/9f2c….png",
"defaultPriority": 5,
"lastUsed": "2025-01-15T12:00:00Z",
"sortKey": "a0",
"tags": ["prod"],
"hbTotal": 2,
"hbStatus": "ok"
}
]

Поля канала:

ПолеОписание
tokenПервичный ключ канала; у расшаренного канала — собственный S…-токен получателя (пусто при праве view)
imageПубличный URL логотипа (пусто, если не загружен)
sortKeyКлюч ручной сортировки
parentIdРодительский канал (дерево каналов); нет у корневого
tagsТеги канала
deliveryConfigНастройки доставки; секреты адаптеров замаскированы
shared, sharePermission, canShareТолько у расшаренных вам каналов: признак, уровень доступа (view|send) и право делиться дальше
hbTotal, hbAlerting, hbAlertingInfo, hbPending, hbStatusСводка heartbeat-ов канала; hbStatus — ok|degraded|alerting|pending|none
Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/application \
-H "Content-Type: application/json" \
-d '{"name": "CI/CD", "description": "Уведомления о сборках", "defaultPriority": 5}'

Поля запроса (JSON; name, description, defaultPriority, parentId, sortKey можно передать и формой):

ПолеТипОбязательноеОписание
namestring✓Название канала
descriptionstringОписание
defaultPriorityintegerПриоритет по умолчанию — подставляется в сообщения без priority
parentIdintegerРодительский канал (дерево каналов)
sortKeystringКлюч ручной сортировки
tagsstring[]Теги канала (до 10, [a-z0-9_-]) — используются скоупом API-токенов
deliveryConfigobjectДосылка непрочитанного на email/SMS/звонок/Slack/Telegram/webhook/Discord/Teams/Mattermost/PagerDuty/Opsgenie — см. Доставка
Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/application/1 \
-X PUT -H "Content-Type: application/json" \
-d '{"name": "CI/CD v2", "description": "Обновлённое описание"}'
Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/application/1 -X DELETE

Возвращает агрегированный статус канала (heartbeat-сводка, последняя активность). С ?recursive=1 — по каналу и всем его потомкам.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/application/1/status

POST /application/{id}/delivery/test — тест доставки во внешние интеграции

Заголовок раздела «POST /application/{id}/delivery/test — тест доставки во внешние интеграции»

Немедленно (в обход эскалации) отправляет тестовое уведомление через включённые способы доставки канала (email, SMS, звонок, Slack, Telegram, webhook, Discord, Teams, Mattermost, PagerDuty, Opsgenie) и возвращает результат по каждому. Опциональное тело {"adapter": "slack"} ограничивает проверку одним адаптером. Подробно — Доставка и эскалация.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/application/1/delivery/test \
-H "Content-Type: application/json" -d '{"adapter": "telegram"}'
{"results": {"telegram": {"ok": true}, "slack": {"ok": false, "error": "..."}}}

Если включённых методов нет — 400 no enabled adapter to test.

GET /application/{id}/event-sources — источники событий канала

Заголовок раздела «GET /application/{id}/event-sources — источники событий канала»

Всё, что пишет в канал: мониторы всех типов, heartbeat-ы, сканы портов, метрики, web-скрипты, правила почтовых ящиков и webhook-роутера — одним списком, с текущим статусом и временем последней проверки. Секреты источников (токены, заголовки, шаги) в выдачу не попадают. С ?recursive=1 — включая потомков канала.

Метод и путьОписание
POST /application/{id}/imageЗагрузить логотип канала (multipart/form-data, поле file)
DELETE /application/{id}/imageУдалить логотип

Тело — только JSON (Content-Type: application/json): form-data и urlencoded эта ручка сейчас не принимает (400).

Окно терминала
curl "https://api.notifly.ru/message?token=ApNK7NiI0ltrJf3a8BNsOiD" \
-H "Content-Type: application/json" \
-d '{"message": "Сборка #42 завершена", "title": "CI/CD", "priority": 5}'

Поля запроса:

ПолеТипОбязательноеОписание
messagestring✓Текст сообщения
titlestringЗаголовок
priorityintegerПриоритет (0–10); если не указан — defaultPriority канала
extrasobjectДополнительные поля для клиентов (см. msgextras)

Пример с extras (markdown-контент):

Окно терминала
curl "https://api.notifly.ru/message?token=ApNK7NiI0ltrJf3a8BNsOiD" \
-H "Content-Type: application/json" \
-d '{
"message": "**Готово!** Подробности: [ссылка](https://example.com)",
"title": "Сборка",
"priority": 5,
"extras": {
"client::display": {"contentType": "text/markdown"}
}
}'

Ответ:

{
"id": 123,
"appid": 1,
"message": "Сборка #42 завершена",
"title": "CI/CD",
"priority": 5,
"date": "2025-06-01T10:30:00Z",
"senderName": "user@example.com"
}

Каждое сообщение списывает одно событие дневной квоты; при исчерпании — 429 daily event quota exceeded. Запись в служебный канал запрещена — 403.

POST /integrations/alertmanager, POST /integrations/zabbix — приём из систем мониторинга

Заголовок раздела «POST /integrations/alertmanager, POST /integrations/zabbix — приём из систем мониторинга»

Нативные приёмники алертов с авторизацией app-токеном канала (заголовок X-Notifly-Key, Authorization: Bearer или ?token=), как у POST /message.

  • /integrations/alertmanager — тело webhook Prometheus Alertmanager (version 4) или webhook contact point Grafana; создаёт сообщение для firing-алертов и отдельное — для resolved.
  • /integrations/zabbix — параметры media type Zabbix «Webhook» (subject, message, severity, status, …); одно сообщение.

Приоритет выводится из severity источника, каждое сообщение списывает одно событие квоты. Ответ — {"created": N, "ids": [...]}. Настройка и маппинг — Alertmanager, Grafana и Zabbix.

Сообщения всех доступных каналов (своих и расшаренных вам), новые первыми. API-токен видит только каналы своего скоупа, токен канала — только свой канал.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" "https://api.notifly.ru/message?limit=20"

Параметры:

ПараметрТипПо умолчаниюОписание
limitinteger100Количество сообщений (1–200)
sinceintegerКурсор пагинации: вернуть сообщения с ID меньше указанного. Берётся из paging.since / paging.next предыдущей страницы

Ответ:

{
"paging": {
"size": 20,
"limit": 20,
"since": 4012,
"next": "/message?limit=20&since=4012"
},
"messages": [
{
"id": 4031,
"appid": 1,
"message": "Текст сообщения",
"title": "Заголовок",
"priority": 5,
"date": "2025-06-01T10:30:00Z",
"read": true,
"senderName": "user@example.com"
}
]
}

paging.since и paging.next есть только когда следующая страница существует; на последней странице их нет. В сообщении read: true — прочитано текущим пользователем (у непрочитанных поля нет), senderName — отправитель, extras — если были переданы.

Та же пагинация и формат ответа, что у GET /message. С ?recursive=1 — сообщения канала и всех его потомков (получателю шары — только расшаренных ему).

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" "https://api.notifly.ru/application/1/message?limit=50"
curl -H "X-Notifly-Key: $TOKEN" "https://api.notifly.ru/application/1/message?recursive=1"

Ищет по сообщениям пользователя. Параметр q обязателен (минимум 2 символа). Опциональный appId ограничивает поиск одним каналом. Вместе с appId флаг recursive=1 расширяет поиск на канал и всех его потомков (получателю шары — только на расшаренные ему). Поддерживает пагинацию (limit, since). Токен канала ищет только в своём канале.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" "https://api.notifly.ru/message/search?q=ошибка&limit=20"
curl -H "X-Notifly-Key: $TOKEN" "https://api.notifly.ru/message/search?q=deploy&appId=1"
curl -H "X-Notifly-Key: $TOKEN" "https://api.notifly.ru/message/search?q=deploy&appId=1&recursive=1"

POST /message/read — отметить сообщения прочитанными

Заголовок раздела «POST /message/read — отметить сообщения прочитанными»

Тело: {"ids": [1, 2, 3]} — список ID сообщений. Отметка владельца останавливает досылку; read-only API-токен сюда не допускается.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/message/read \
-H "Content-Type: application/json" -d '{"ids": [1, 2, 3]}'

POST /application/{id}/message/read — отметить весь канал прочитанным

Заголовок раздела «POST /application/{id}/message/read — отметить весь канал прочитанным»

С ?recursive=1 — вместе с потомками.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/application/1/message/read -X POST

Недоступно API-токену с ограниченным скоупом.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/message -X DELETE
Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/message/123 -X DELETE

DELETE /application/{id}/message — удалить все сообщения канала

Заголовок раздела «DELETE /application/{id}/message — удалить все сообщения канала»

С ?recursive=1 — вместе с потомками.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/application/1/message -X DELETE

Клиент — это устройство или приложение, которое получает сообщения и управляет ресурсами.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/client
[
{
"id": 1,
"name": "firefox",
"token": "C…xiLx",
"lastUsed": "2025-06-01T10:00:00Z",
"status": "active",
"createdAt": "2025-05-20T08:00:00Z",
"platform": "web",
"lastIp": "203.0.113.7",
"lastUserAgent": "Mozilla/5.0 …",
"current": true
}
]

token в списке — только метка, не секрет. Полное значение токена отдаётся один раз: в ответах POST /auth/local/login, POST /client и POST /client/{id}/reconnect. status — active|suspended|revoked, current: true — устройство, от имени которого сделан запрос.

Тело: name (обязательно), platform. Ответ — созданный клиент с полным токеном. При исчерпанном лимите устройств тарифа — 402 с errorCode: "device_limit_exceeded".

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/client \
-H "Content-Type: application/json" \
-d '{"name": "my-script"}'
Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/client/1 \
-X PUT -H "Content-Type: application/json" \
-d '{"name": "renamed-client"}'
Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/client/1 -X DELETE

DELETE /client — удалить все устройства, кроме текущего

Заголовок раздела «DELETE /client — удалить все устройства, кроме текущего»

Ответ — {"deleted": N}.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/client -X DELETE

Состояние устройств и отключённые каналы

Заголовок раздела «Состояние устройств и отключённые каналы»

По умолчанию устройство получает сообщения всех каналов. «Подписки» в путях ниже — это исторические имена: на деле это список отключённых (заглушённых) на устройстве каналов.

Метод и путьОписание
GET /client/onlineСписок id устройств с активным WS-соединением
POST /client/{id}/reconnectРотировать токен устройства; новый токен возвращается один раз
PUT /client/{id}/statusСменить статус, тело {"status": "active|suspended|revoked"}; revoked необратим, реактивация сверх лимита — 402
GET /client/{id}/activityЖурнал активности устройства (?from=&to=&type=&limit=, даты RFC3339)
GET /client/{id}/subscriptionsКаналы, отключённые на устройстве
PUT /client/{id}/subscriptionsЗаменить список отключённых каналов, тело {"channelIds": [1, 2]} (пустой массив — включить все)

Самообслуживание устройства (аутентификация по токену самого устройства):

Метод и путьОписание
GET /device/me/subscriptionsКаналы, отключённые на этом устройстве
POST /device/me/subscriptionsОтключить канал, тело {"channelId": 1}
DELETE /device/me/subscriptions/{channel_id}Снова включить канал

GET /current/user — информация о текущем пользователе

Заголовок раздела «GET /current/user — информация о текущем пользователе»
Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/current/user
{
"id": 1,
"email": "user@example.com",
"admin": false,
"verified": true,
"plan": "free",
"eventCounter": 120,
"messageCounter": 80,
"heartbeatCounter": 30,
"monitorCounter": 10,
"webScriptCounter": 0,
"balanceKopecks": 0,
"storageBytes": 0,
"image": "",
"mfaEnabled": false
}

Чувствительные действия (смена пароля, настройки 2FA, админские ручки) требуют свежего подтверждения. Без него ответ — 403 с "reason": "sudo_required" и списком доступных methods. Подтверждение открывает окно на 15 минут для этого устройства.

Только токен устройства: API-токену и токену канала окно не выдаётся (403).

ПолеОписание
methodpassword — если 2FA выключена; totp или recovery — если включена (пароль не принимается)
passПароль (для password)
codeКод аутентификатора или recovery-код
Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/current/user/sudo \
-H "Content-Type: application/json" \
-d '{"method": "password", "pass": "current-password"}'
{"ok": true, "method": "password", "expiresIn": 900}

Неверный пароль — 400 wrong password, неверный код — 401 invalid code.

Требует токен устройства и sudo-окно; API-токен получает 403. Текущий пароль oldPass обязателен, новый pass — от 8 символов и не длиннее 72 байт.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/current/user/password \
-H "Content-Type: application/json" \
-d '{"pass": "new-secure-password", "oldPass": "current-password"}'

Неверный oldPass — 400 с errorDescription: "wrong password". После успешной смены остальные устройства разлогиниваются (их токены ротируются), а сессия, из которой пришёл запрос, продолжает работать; открытые sudo-окна закрываются. API-токены смена пароля не трогает — в отличие от сброса по письму.

Все ручки — только токеном устройства; помеченные «sudo» требуют sudo-окна.

Метод и путьОписание
GET /current/user/mfaСостояние: enabled, pendingSetup, recoveryCodesRemaining, mobileConnected, mobileEnabled, approverDevices
POST /current/user/mfa/setupsudo. Новый секрет аутентификатора: {"secret", "uri"} (otpauth://…); 2FA уже включена — 409
POST /current/user/mfa/confirmsudo. Включить 2FA первым кодом, тело {"code": "123456"}; ответ — {"recoveryCodes": [...]}
POST /current/user/mfa/disablesudo. Выключить 2FA
POST /current/user/mfa/recovery-codessudo. Перевыпустить recovery-коды
POST /current/user/mfa/mobile/startsudo. Начать привязку телефона для подтверждения входов: {"challenge", "code", "expiresIn"}
POST /current/user/mfa/mobile/confirmЗавершить привязку после того, как телефон ввёл code через /auth/mfa/approve, тело {"challenge": "…"}
POST /current/user/mfa/mobile/disablesudo. Выключить подтверждение входов с телефона
DELETE /current/user/mfa/mobile/devices/{id}sudo. Убрать устройство из подтверждающих

Подробности о тарифах и лимитах — на странице Квоты и тарифы.

Метод и путьОписание
GET /user/quota-breakdownДетальная разбивка расхода событий за день (?day=YYYY-MM-DD), почасовая и поминутная, плюс снимок занятого хранилища (storage)
POST /current/user/planСменить тариф, тело {"plan": "free|pro|business"}. Самостоятельно — только понизить или оставить текущий; повышение — 402 plan upgrade requires payment
POST /current/user/topupПополнение баланса, тело {"amountRubles": N}. Не администратору — 402 с реквизитами оплаты (paymentMethod: "bank_transfer")
POST /current/user/imageЗагрузить аватар (multipart/form-data, поле file)
DELETE /current/user/imageУдалить аватар

Платёжного шлюза нет: повышение тарифа и пополнение баланса — оплата по счёту (банковский перевод), после которой оператор переводит аккаунт на новый тариф (POST /user/{id}/plan).

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" "https://api.notifly.ru/user/quota-breakdown?day=2026-06-23"
# Понизить тариф до free
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/current/user/plan \
-H "Content-Type: application/json" -d '{"plan": "free"}'

Ответ POST /current/user/topup не администратору:

{
"message": "Пополните баланс переводом на указанные реквизиты",
"amountRubles": 500,
"paymentMethod": "bank_transfer"
}

Подробнее — Тихие часы и дайджест.

Метод и путьОписание
GET /current/user/quiet-hoursТекущие настройки (у нового пользователя: enabled: false, 23:00–08:00)
PUT /current/user/quiet-hoursСохранить; неприсланные поля сохраняют значения; ответ — сохранённый объект

Тело: enabled, timezone (IANA), start/end (HH:MM, конец раньше начала — через полночь), days (ISO 1=пн…7=вс, по дню начала), breakthroughPriority (0..10), digest.

Окно терминала
curl -X PUT -H "X-Notifly-Key: $TOKEN" -H "Content-Type: application/json" \
https://api.notifly.ru/current/user/quiet-hours \
-d '{"enabled":true,"timezone":"Europe/Moscow","start":"23:00","end":"08:00","days":[1,2,3,4,5,6,7],"breakthroughPriority":8,"digest":true}'

Управление пользователями (администратор)

Заголовок раздела «Управление пользователями (администратор)»

Постранично, keyset по возрастанию id: limit (1–200, по умолчанию 100) и since — id последнего пользователя предыдущей страницы.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" "https://api.notifly.ru/user?limit=100"
{
"paging": {"size": 2, "limit": 100},
"users": [
{
"id": 1,
"email": "admin@example.com",
"admin": true,
"verified": true,
"plan": "business",
"mfaEnabled": true
},
{
"id": 2,
"email": "user1@example.com",
"admin": false,
"verified": true,
"plan": "free",
"mfaEnabled": false
}
]
}

Пользователь — в том же формате, что у GET /current/user (в примере поля сокращены).

Созданный администратором пользователь сразу подтверждён; при самостоятельной регистрации на адрес уходит письмо с подтверждением.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/user \
-H "Content-Type: application/json" \
-d '{"email": "newuser@example.com", "pass": "password123", "admin": false}'

Тело: email (обязательно, текущий адрес — сменить его нельзя), admin (передавайте текущее значение: отсутствие поля означает false), pass (необязательно, новый пароль), resetMfa (сбросить 2FA пользователя). Смена пароля администратором работает как сброс: все устройства пользователя разлогиниваются, все его API-токены удаляются.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/user/2 \
-H "Content-Type: application/json" \
-d '{"email": "user1@example.com", "admin": false, "pass": "new-password-123"}'

Операторская смена тарифа, в том числе повышение после оплаты. Тело {"plan": "free|pro|business"}.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/user/2/plan \
-H "Content-Type: application/json" -d '{"plan": "pro"}'

Удалить самого себя нельзя (400).

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/user/2 -X DELETE

Dead-man-switch: внешняя задача (cron, скрипт) периодически шлёт «пинг»; если пинг не приходит вовремя, Notifly присылает алерт. Подробнее — Heartbeat.

Публичный пинг (аутентификация по ping-токену H… в URL, без API-токена):

Окно терминала
curl https://api.notifly.ru/heartbeat/ping/HrvF2iYjEnz5z8ZngHvvkX3 # GET — удобно из cron
curl -X POST https://api.notifly.ru/heartbeat/ping/HrvF2iYjEnz5z8ZngHvvkX3 \
-H "Content-Type: application/json" -d '{"fail_reason": "backup failed"}'

Управление (API-токен):

Метод и путьОписание
GET /heartbeatСписок heartbeat-ов
POST /heartbeatСоздать
PUT /heartbeat/{id}Обновить
DELETE /heartbeat/{id}Удалить
POST /heartbeat/{id}/pause · /resumeПриостановить / возобновить
POST /heartbeat/{id}/test-alert · /test-recoveryТестовое алерт- / recovery-уведомление

Активные проверки доступности и контента. Каждый тип имеет свою страницу с деталями.

Метод и путьОписание
GET /monitor · POST /monitorСписок / создать
POST /monitor/testПроверить настройки без сохранения
PUT /monitor/{id} · DELETE /monitor/{id}Обновить / удалить
POST /monitor/{id}/pause · /resumeПриостановить / возобновить
Метод и путьОписание
GET /http-monitor · POST /http-monitorСписок / создать
POST /http-monitor/testПроверить запрос
PUT /http-monitor/{id} · DELETE /http-monitor/{id}Обновить / удалить
POST /http-monitor/{id}/pause · /resumeПриостановить / возобновить
Метод и путьОписание
GET /content-monitor · POST /content-monitorСписок / создать
POST /content-monitor/suggest-selectorИИ-подбор CSS-селектора
POST /content-monitor/test-ruleПроверить правило
PUT /content-monitor/{id} · DELETE /content-monitor/{id}Обновить / удалить
POST /content-monitor/{id}/pause · /resumeПриостановить / возобновить
Метод и путьОписание
GET /port-monitor · POST /port-monitorСписок / создать
POST /port-monitor/testПроверить порт
PUT /port-monitor/{id} · DELETE /port-monitor/{id}Обновить / удалить
POST /port-monitor/{id}/pause · /resumeПриостановить / возобновить
Метод и путьОписание
GET /port-scan · GET /port-scan/{id}Список / один скан
POST /port-scanЗапустить скан
PATCH /port-scan/{id} · DELETE /port-scan/{id}Обновить / удалить
POST /port-scan/{id}/cancel · /restartОтменить / перезапустить
POST /port-scan/{id}/to-monitorПревратить найденный порт в монитор
Метод и путьОписание
GET /workflow-monitor · POST /workflow-monitorСписок / создать
POST /workflow-monitor/build-stepИИ-сборка шага
POST /workflow-monitor/testПрогнать сценарий
PUT /workflow-monitor/{id} · DELETE /workflow-monitor/{id}Обновить / удалить
POST /workflow-monitor/{id}/pause · /resumeПриостановить / возобновить
Метод и путьОписание
GET /browser-workflow · POST /browser-workflowСписок / создать
POST /browser-workflow/build-stepИИ-подбор действия
POST /browser-workflow/loginЗахват cookie авторизации
POST /browser-workflow/test-stepПроверить шаг
PUT /browser-workflow/{id} · DELETE /browser-workflow/{id}Обновить / удалить
POST /browser-workflow/{id}/pause · /resumeПриостановить / возобновить

GET /browser-shot/{key} отдаёт JPEG-скриншот сбоя браузерного workflow или браузерного монитора контента. key берётся из поля notifly::screenshot в extras алерт-сообщения. Доступ — только владельцу монитора; для <img> токен можно передать в ?token=. Старые скриншоты вычищаются ретенцией — тогда 404.

Окно терминала
curl -H "X-Notifly-Key: $TOKEN" -o shot.jpg \
"https://api.notifly.ru/browser-shot/<значение notifly::screenshot>"

Подтверждение владения хостом перед сканированием/мониторингом.

Метод и путьОписание
GET /verified-hostСписок
POST /verified-host/start · /checkНачать / проверить подтверждение
DELETE /verified-host/{id}Удалить

{kind} — тип монитора (monitor, http-monitor, content-monitor, port-monitor и т. д.).

Метод и путьОписание
GET /monitor-history/{kind}/{id}Uptime %, время отклика, агрегаты
GET /monitor-history/{kind}/{id}/logПодробный лог отдельных проверок

Входящее письмо на адрес ящика превращается в уведомление. Подробнее — Email Inbox.

Метод и путьОписание
GET /email-inbox · POST /email-inboxСписок / создать ящик
PUT /email-inbox/{id} · DELETE /email-inbox/{id}Обновить / удалить
GET /email-inbox/{id}/rules · POST /email-inbox/{id}/rulesПравила обработки писем
PUT /email-inbox/{id}/rules/{rid} · DELETE /email-inbox/{id}/rules/{rid}Обновить / удалить правило
GET /email-inbox/eventИстория входящих писем
GET /email-inbox/event/{eid} · DELETE /email-inbox/event/{eid}Письмо / удалить
POST /email-inbox/rule/from-event/{eid}ИИ-подсказка правила по письму

JS-сниппеты для сайта: трекинг ошибок (console_errors), события и т. п. Подробнее — Web-скрипт.

Публичный ingest (аутентификация по токену в URL, отправка из браузера). GET и POST без тела тоже работают — скрипт срабатывает со своими настройками по умолчанию:

Окно терминала
curl -X POST https://api.notifly.ru/script/<token> \
-H "Content-Type: application/json" -d '{ ... }'
curl https://api.notifly.ru/script/<token>

Управление (API-токен):

Метод и путьОписание
GET /web-script · POST /web-scriptСписок / создать
PUT /web-script/{id} · DELETE /web-script/{id}Обновить / удалить
GET /web-script/{id}/sourcemaps · POST /web-script/{id}/sourcemapsSource maps
DELETE /web-script/{id}/sourcemaps/{smid}Удалить source map
GET /web-script/{id}/issuesСгруппированные ошибки (issues)
GET /web-script/{id}/issue-countЧисло нерешённых issue ({"unresolved": N})
POST /web-script/{id}/issues/{iid}/resolve · /ignoreПометить issue решённым / игнорируемым
DELETE /web-script/{id}/issues/{iid}Удалить issue
GET /web-script/{id}/issues/{iid}/breadcrumbsДействия пользователя перед ошибкой
POST /web-script/{id}/issues/{iid}/analyzeAI-разбор причины (тело: lang, force)
GET /web-script/{id}/issues/{iid}/analysisСохранённый разбор (204, если его нет)
GET /web-script/{id}/series · /error-seriesТайм-серии срабатываний и ошибок (?bucket=1m|1h|1d&from=&to=)
GET /web-script/{id}/flush-statsРаспределение причин отправки батчей

Принимает входящие вебхуки и маршрутизирует их по правилам в каналы. Это singleton на пользователя с path-based маршрутизацией. Подробнее — Webhook-роутер.

Публичный приём (аутентификация по токену R… в URL, любой путь после токена; принимается и GET без тела):

Окно терминала
curl -X POST https://api.notifly.ru/router/<token>/любой/путь \
-H "Content-Type: application/json" -d '{ ... }'

Управление (API-токен):

Метод и путьОписание
GET /webhook-router · PUT /webhook-routerПолучить / обновить роутер
POST /webhook-router/rotate-tokenСменить публичный токен
GET /webhook-router/rule · POST /webhook-router/ruleПравила маршрутизации
PUT /webhook-router/rule/{rid} · DELETE /webhook-router/rule/{rid}Обновить / удалить правило
GET /webhook-router/event · GET /webhook-router/event/{eid}История событий
DELETE /webhook-router/event/{eid}Удалить событие
GET /webhook-router/message · DELETE /webhook-router/message/{mid}Маршрутизированные сообщения
POST /webhook-router/rule/from-event/{eid}ИИ-подсказка правила по событию

Числовые временные ряды с алертами. Подробнее — Метрики.

Публичный приём метрики (аутентификация по токену источника M… в URL — это не API-токен):

Окно терминала
curl -X POST https://api.notifly.ru/metric/<token> \
-H "Content-Type: application/json" -d '{ ... }'

Управление (API-токен):

Метод и путьОписание
GET /metric-source · POST /metric-sourceИсточники метрик
PUT /metric-source/{id} · DELETE /metric-source/{id}Обновить / удалить источник
GET /metric-source/{id}/metricsМетрики источника
PATCH /metric-source/{id}/metrics/{mid} · DELETE /metric-source/{id}/metrics/{mid}Тип / удалить метрику
GET /metric-source/{id}/metrics/{mid}/seriesВременной ряд значений
GET /metric-source/{id}/alerts · POST /metric-source/{id}/alertsАлерты по метрике
PUT /metric-source/{id}/alerts/{aid} · DELETE /metric-source/{id}/alerts/{aid}Обновить / удалить алерт

Предоставление другим пользователям доступа к каналу по email. Подробнее — Доступ к каналам.

Метод и путьОписание
GET /application/{id}/share · POST /application/{id}/shareСписок / создать шару на канал
PUT /share/{id} · DELETE /share/{id}Обновить / отозвать шару
GET /share/incomingШары, предоставленные мне
GET /share/recipientsАдреса, с кем я уже делился (подсказки)
POST /share/{id}/accept · /declineПринять / отклонить шару
POST /share/joinПрисоединиться по токену
POST /share/leaveОтказаться от доступа к каналу, тело {"appid": N}
POST /share/rotateСменить значение своего Share-токена, тело {"appid": N}

Несколько ключей на канал с раздельными правами, мягким отзывом и ротацией. Доступно только владельцу канала.

Метод и путьОписание
GET /application/{id}/token · POST /application/{id}/tokenСписок / выдать ключ. Body: name, canRead, canWrite, note, expiresAt (unix ms, 0 — бессрочно)
PUT /token/{id}Изменить права, метку и срок
DELETE /token/{id}Отозвать ключ (повторный вызов удаляет запись; первичный ключ канала → 409)
POST /token/{id}/rotateСменить значение, сохранив id и права

Публичная страница со статусом и аптаймом мониторов канала. Подробнее — Статус-страницы.

Управление (API-токен, только владелец канала):

Метод и путьОписание
GET /status-pageСписок своих статус-страниц
POST /status-pageСоздать. Body: appid, slug, title, description, enabled, lang (ru|en), brandingHidden
PUT /status-page/{id}Обновить (тот же payload)
DELETE /status-page/{id}Удалить

Публичные эндпоинты (без авторизации):

Метод и путьОписание
GET /status/{slug}HTML-страница статуса
GET /status/{slug}/summaryТот же срез в JSON: overall, overallUptime90d, services[], incidents[]
POST /status/{slug}/subscribeПодписка по email (double opt-in), тело {"email": "..."}
GET /status-subscribe/verify?token=…Подтвердить подписку (ссылка из письма)
GET /status-subscribe/unsub?token=…Отписаться (ссылка из письма)
Окно терминала
curl -H "X-Notifly-Key: $TOKEN" https://api.notifly.ru/status-page \
-H "Content-Type: application/json" \
-d '{"appid": 1, "slug": "acme-status", "title": "Статус ACME", "enabled": true, "lang": "ru"}'
curl https://api.notifly.ru/status/acme-status/summary

Коды: 400 — некорректный slug/язык или чужой канал, 403 — лимит тарифа или премиум-поле не по плану, 404 — страница не найдена или не опубликована, 409 — slug занят.


Плановые работы: мониторы охвата не алертят, сообщения не эскалируются и приходят беззвучно, статус-страница показывает «Плановые работы». Подробнее — Окна обслуживания.

Метод и путьОписание
GET /maintenance-windowСписок своих окон
POST /maintenance-windowСоздать
GET /maintenance-window/{id}Одно окно
PUT /maintenance-window/{id}Заменить поля
DELETE /maintenance-window/{id}Удалить (204)

Тело: name, channelIds[], includeSubtree, monitors[] ({"kind","id"}), schedule (once — startsAt/endsAt; weekly — timezone, days, start, end), enabled. В ответе дополнительно active, nextStart, nextEnd, coveredChannelIds.

Окно терминала
curl -X POST -H "X-Notifly-Key: $TOKEN" -H "Content-Type: application/json" \
https://api.notifly.ru/maintenance-window \
-d '{"name":"Релиз","channelIds":[12],"includeSubtree":true,"monitors":[],"schedule":"once","startsAt":"2026-10-02T23:00:00Z","endsAt":"2026-10-03T01:00:00Z","enabled":true}'

Коды: 400 — ошибка валидации или чужой канал/монитор, 403 — лимит или неподходящий API-токен, 404 — окна нет или оно чужое.


Программные ключи аккаунта (M…) для SDK, CLI и MCP. Выпускаются из админки; подробности — на странице API-токены. Управлять ими можно только токеном устройства: сам API-токен к этим ручкам не допускается (403).

Метод и путьОписание
GET /api-tokenСписок; поле token — метка M…ab3d, не секрет
POST /api-tokenВыпустить; единственный ответ с полным значением
PUT /api-token/{id}Изменить название, доступ, скоуп, срок
POST /api-token/{id}/rotateПеревыпустить: новое значение, прежние настройки
DELETE /api-token/{id}Удалить

Тело POST/PUT:

ПолеТипОписание
namestringНазвание (обязательно)
accessstringread или write (обязательно)
appIdsint[]Разрешённые каналы по id
appTagsstring[]Разрешённые каналы по тегам; пустые appIds и appTags — все каналы. В PUT отсутствие поля — не менять
expiresAtstringСрок действия, RFC3339, в будущем; в PUT отсутствие поля — не менять
Окно терминала
curl -H "X-Notifly-Key: $DEVICE_TOKEN" https://api.notifly.ru/api-token \
-H "Content-Type: application/json" \
-d '{"name": "ci", "access": "write", "appTags": ["prod"], "expiresAt": "2027-01-01T00:00:00Z"}'

Интерактивные вопросы: канал спрашивает — пользователь отвечает из интерфейса. Подробнее — Ask.

Отправка вопроса использует app-токен:

Метод и путьАутентификацияОписание
POST /askapp-токенЗадать вопрос от имени канала
GET /ask/pending-answersapp-токенЗабрать готовые ответы
POST /ask/ackapp-токенПодтвердить получение ответов
GET /ask-question/{id}app-токенУзнать ответ на конкретный вопрос (истёк или отменён — 410)
POST /ask-question/{id}/answerAPI-токенОтветить на вопрос из UI
DELETE /ask-question/{id}API-токенОтменить вопрос
POST /message/{id}/answerAPI-токенОтветить на вопрос из сообщения
POST /ask-question/{id}/extendтокен устройства, API или каналаПродлить срок ответа, тело {"timeout_sec": 1…86400}; токен канала — с правом записи
GET /a/answer?token=…подписанная ссылкаОтвет по кнопке из письма или Telegram
GET /m/read?token=…подписанная ссылкаОтметить сообщение прочитанным (останавливает досылку)

Чат-копайлот для онбординга и помощи. Подробнее — Ассистент.

Метод и путьОписание
GET /assistant/threadsСписок бесед
GET /assistant/threads/{id}/messagesИстория сообщений беседы
DELETE /assistant/threads/{id}Удалить беседу
POST /assistant/chatОтправить сообщение ассистенту
GET /assistant/insightsПроактивные рекомендации по аккаунту (?polish=1, ?refresh=1, ?lang=)

Есть два независимых канала live-обновлений. Подробнее — на странице WebSocket.

Основной канал доставки push-сообщений в реальном времени. Подключение — по токену в query-параметре token (обычно токен устройства; другие варианты — на странице WebSocket):

Окно терминала
# С помощью wscat
wscat -c "wss://api.notifly.ru/ws?token=CK2UDmhduKshCyz-RtqxiLx"
const ws = new WebSocket('wss://api.notifly.ru/ws?token=CK2UDmhduKshCyz-RtqxiLx');
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log(`[${msg.title}] ${msg.message} (приоритет: ${msg.priority})`);
};

Каждое входящее событие — JSON-объект Message:

{
"id": 124,
"appid": 1,
"message": "Новое сообщение",
"title": "Заголовок",
"priority": 5,
"date": "2025-06-01T10:31:00Z"
}

Отдельный эндпоинт Server-Sent Events (GET /stream, Content-Type: text/event-stream) для live-обновления интерфейсов: он сообщает, что что-то изменилось, а сами сообщения приходят по WebSocket. Сервер шлёт только именованные события — connected, channel:status_changed, share:changed (данные — {"appid": N}) — и раз в 25 секунд keepalive-комментарий. Обработчик onmessage их не получает: подписывайтесь через addEventListener.

Аутентификация — токен в ?token= либо cookie сессии на странице того же сайта. Для cross-origin запросов cookie не отправится (withCredentials работает только для origin-ов из серверной настройки CORS_ALLOWED_ORIGINS), поэтому снаружи используйте ?token=.

const es = new EventSource('https://api.notifly.ru/stream?token=CK2UDmhduKshCyz-RtqxiLx');
es.addEventListener('connected', () => console.log('подключено'));
es.addEventListener('channel:status_changed', (e) => {
console.log('статус канала изменился', JSON.parse(e.data).appid);
});
es.addEventListener('share:changed', (e) => {
console.log('изменился доступ к каналу', JSON.parse(e.data).appid);
});

На развёртываниях в AWS /stream недоступен и отвечает 503 — используйте WebSocket.


Сообщения отправляются только JSON-телом.

import requests
API = "https://api.notifly.ru"
# Отправить сообщение (токен канала)
requests.post(f"{API}/message", params={"token": "ApNK7NiI0ltrJf3a8BNsOiD"}, json={
"title": "Бэкап",
"message": "Резервное копирование завершено",
"priority": 2,
})
# Получить сообщения (API-токен)
resp = requests.get(f"{API}/message", headers={"X-Notifly-Key": "MtVOKLDNuD7HR9y7QkMecC5"})
for msg in resp.json()["messages"]:
print(f"[{msg['title']}] {msg['message']}")
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]any{
"title": "Deploy",
"message": "Версия 2.0 развёрнута",
})
http.Post("https://api.notifly.ru/message?token=ApNK7NiI0ltrJf3a8BNsOiD",
"application/json", bytes.NewReader(body))
}
// Отправить сообщение
const resp = await fetch('https://api.notifly.ru/message?token=ApNK7NiI0ltrJf3a8BNsOiD', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
title: 'CI',
message: 'Тесты пройдены',
priority: 3,
}),
});
console.log(await resp.json());
Окно терминала
# Отправить сообщение
$body = @{
title = "Отчёт"
message = "Ежедневный отчёт сгенерирован"
priority = 1
} | ConvertTo-Json
Invoke-RestMethod -Uri "https://api.notifly.ru/message?token=ApNK7NiI0ltrJf3a8BNsOiD" `
-Method POST -ContentType "application/json; charset=utf-8" -Body $body

КодЗначение
200Успешно
204Успешно, тела нет (например, удаление окна обслуживания)
400Некорректный запрос (неверные параметры, неверный пароль при переспросе)
401Не авторизован (отсутствует или невалидный токен, нужен второй фактор, неверный код 2FA)
402Нужна оплата: повышение тарифа, пополнение баланса, лимит устройств тарифа
403Запрещено: недостаточно прав, неподходящий тип токена, нужен sudo ("reason": "sudo_required"), лимит тарифа
404Ресурс не найден (в том числе чужой)
409Конфликт: slug занят, вопрос уже не ожидает ответа, 2FA уже включена, отзыв первичного ключа канала
410Больше не действует: вопрос истёк или отменён, MFA-challenge истёк или использован
429Слишком много запросов: исчерпана дневная квота событий (daily event quota exceeded) или сработал rate limit (заголовок Retry-After)
503Временно недоступно: /health при недоступной базе, /stream на AWS