Публичные статус-страницы
Статус-страница — это публичный адрес вида /status/<slug>, на котором любой
человек (клиент, коллега, подписчик) видит, работают ли ваши сервисы. Данные
берутся из уже настроенных мониторов и
heartbeat-ов выбранного канала: ничего дополнительно
настраивать и слать не нужно.
Страница отдаётся сервером как готовый HTML — без авторизации, без JS-фреймворка и без обращения к админке.
Что показывает страница
Заголовок раздела «Что показывает страница»- Общий баннер — «Все системы работают» / «Частичная деградация» / «Сбои в работе сервисов» / «Идут плановые работы» и средний аптайм за 90 дней.
- Список сервисов — по одной строке на монитор или heartbeat: имя, тип, цветная отметка статуса, аптайм за 90 дней, средний отклик за 30 дней и полоса из 90 дневных ячеек (подсказка ячейки — дата и процент). Сервис в окне обслуживания помечен «Плановые работы». Аптайм за 30 дней есть в JSON-срезе.
- Лента инцидентов — последние 20 авто-инцидентов со временем начала и длительностью («Инцидент» — ещё идёт, «Восстановлено» — закрыт).
- Форма подписки — посетитель оставляет email и получает письмо при каждом инциденте и восстановлении.
- Подвал — время обновления и бейдж «powered by Notifly» (ссылка на
notifly.ru с UTM-метками
utm_source=statuspage&utm_medium=badge&utm_campaign=<slug>); бейдж можно скрыть на тарифах Pro и Business.
посетитель ──GET /status/<slug>────▶ server-rendered HTML (без авторизации) GET /status/<slug>/summary ──▶ тот же срез в JSON (для авто-обновления)
мониторы канала ──переход up↔down──▶ авто-инцидент ──▶ письмо подписчикамЧто попадает на страницу
Заголовок раздела «Что попадает на страницу»Страница привязана к одному каналу. На неё автоматически попадают все источники событий этого канала, которые ведут историю проверок:
| Источник | Тип на странице (kind) |
|---|---|
| Активный монитор (ICMP / TCP / HTTP и т.п.) | собственный вид монитора: icmp, tcp, http, … |
| HTTP-монитор | http |
| Контент-монитор | content |
| Порт-монитор | port |
| Workflow-монитор | workflow |
| Браузерный workflow | browser_workflow |
| Heartbeat | heartbeat |
Статусы и аптайм
Заголовок раздела «Статусы и аптайм»Статус каждого сервиса приводится к единому словарю:
| Статус | Значение |
|---|---|
up | проверки проходят |
degraded | частичная деградация |
down | проверки падают (у heartbeat — пропущен ping) |
pending | проверок ещё не было |
paused | монитор на паузе |
maintenance | сервис в активном окне обслуживания — показывается как «Плановые работы» |
Общий статус страницы собирается по всем сервисам:
- есть хотя бы один
down→down(баннер «Сбои в работе сервисов»); - иначе есть
degraded→degraded; - иначе есть сервис в окне обслуживания →
maintenance(баннер «Идут плановые работы»); - иначе, если сервисы есть →
ok; - сервисов нет вовсе →
none.
Аптайм считается из тех же дневных бакетов проверок, что и
история мониторов: полоса — 90 дневных ячеек (up,
degraded, down, maintenance, nodata), рядом — аптайм за 90 дней и
средний отклик за 30 дней (аптайм за 30 дней — в JSON). Ячейка up — все
проверки дня успешны, down — ни одной успешной, degraded — часть неудачных.
Если данных за день нет, ячейка серая, а процент показывается как —. Провалы проверок внутри окна обслуживания в аптайм не
входят; день, где все провалы пришлись на окно, показывается как maintenance.
Инциденты
Заголовок раздела «Инциденты»Инциденты создаются автоматически; вручную завести инцидент или опубликовать сообщение на странице нельзя.
- монитор перешёл в «падение» (heartbeat — в
alerting) → на каждой статус-странице канала открывается инцидент (status: "open") с именем монитора в заголовке; - монитор восстановился (heartbeat получил ping) → инцидент закрывается
(
status: "resolved", проставляетсяresolvedAt).
Операция идемпотентна: повторное падение при уже открытом инциденте ничего не создаёт, а восстановление без открытого инцидента ничего не закрывает. В ленте показываются последние 20 инцидентов. Текст ошибки проверки к инциденту сохраняется, но на публичную страницу и в письма подписчикам не попадает.
Падение внутри активного окна обслуживания инцидента не открывает. Если источник так и лежит после окна, инцидент откроется вместе с отложенным алёртом.
Создание страницы
Заголовок раздела «Создание страницы»Через админку
Заголовок раздела «Через админку»Раздел Статус-страницы → Создать статус-страницу. Поля диалога:
| Поле | Что задаёт |
|---|---|
| Заголовок | <title> и шапка страницы |
| Slug | адрес: /status/<slug> |
| Канал | чьи мониторы попадут на страницу (только собственные каналы) |
| Описание | подзаголовок под шапкой |
| Язык уведомлений подписчикам | ru или en — язык писем подписчикам и служебных страниц подтверждения/отписки |
| Страница опубликована | выключено = черновик, публичный адрес отвечает 404 |
| Скрыть бейдж «powered by Notifly» | только на тарифах Pro и Business |
В списке страниц видны статус («Опубликована» / «Черновик») и охват —
число просмотров публичной страницы за 30 дней (считаются только открытия
HTML-страницы, опрос /summary не учитывается).
Slug нормализуется сервером: нижний регистр, только a-z, 0-9 и дефис;
пробелы и подчёркивания превращаются в дефисы, повторы схлопываются. Например,
My Status Page → my-status-page. Slug уникален глобально: занятый вернёт
409.
Через REST API
Заголовок раздела «Через REST API»curl -X POST "$NOTIFLY_URL/status-page" \ -H "Content-Type: application/json" \ -H "X-Notifly-Key: <api-token>" \ -d '{ "appid": 12345, "slug": "acme-status", "title": "Статус сервисов ACME", "description": "Актуальное состояние API и сайта", "enabled": true, "lang": "ru", "brandingHidden": false }'Ответ — созданный объект страницы:
{ "id": 987, "appid": 12345, "slug": "acme-status", "title": "Статус сервисов ACME", "description": "Актуальное состояние API и сайта", "enabled": true, "brandingHidden": false, "lang": "ru", "created": "2026-06-23T10:00:00Z", "updated": "2026-06-23T10:00:00Z"}Обязательные поля — appid, slug и title. Страница сразу доступна по
адресу $NOTIFLY_URL/status/acme-status (например,
https://api.notifly.ru/status/acme-status).
Подписка на обновления
Заголовок раздела «Подписка на обновления»Внизу страницы — форма подписки по email. Работает по схеме double opt-in:
- посетитель вводит email →
POST /status/<slug>/subscribe; - на адрес уходит письмо со ссылкой подтверждения
(
GET /status-subscribe/verify?token=…); - после подтверждения подписчик получает письмо при открытии и при закрытии каждого инцидента;
- в каждом письме есть ссылка отписки (
GET /status-subscribe/unsub?token=…).
Повторная подписка тем же адресом не создаёт дубль: подтверждённому подписчику ничего не шлётся, неподтверждённому письмо отправляется заново. Рассылку ведёт тот же минутный воркер доставки, что и эскалацию уведомлений, поэтому письмо приходит в пределах минуты после инцидента.
Письма подписчикам и страницы подтверждения/отписки идут на языке страницы
(поле lang). Интерфейс самой публичной страницы локализуется по заголовку
Accept-Language посетителя (ru/en).
Кэш и авто-обновление
Заголовок раздела «Кэш и авто-обновление»- Агрегат страницы кэшируется на 30 секунд — всплеск трафика не превращается в шторм запросов к базе.
- Открытая страница раз в 45 секунд опрашивает
/status/<slug>/summary. Если общий статус изменился — страница перезагружается, иначе просто обновляется отметка «Обновлено». - Без JavaScript страница перезагружается сама раз в 2 минуты.
JSON для внешних интеграций
Заголовок раздела «JSON для внешних интеграций»GET /status/<slug>/summary отдаёт тот же срез в JSON — удобно для виджета на
своём сайте, дашборда или бота:
curl "$NOTIFLY_URL/status/acme-status/summary"{ "title": "Статус сервисов ACME", "description": "Актуальное состояние API и сайта", "overall": "ok", "overallUptime90d": 99.94, "services": [ { "kind": "http", "name": "API", "status": "up", "uptime30d": 99.98, "uptime90d": 99.94, "avgLatencyMs": 148, "days": [{"date": "2026-03-26", "state": "up", "uptimePct": 100}], "lastCheckAt": "2026-06-23T09:59:12Z" } ], "incidents": [ { "id": 4242, "title": "API", "status": "resolved", "startedAt": "2026-06-21T14:02:00Z", "resolvedAt": "2026-06-21T14:19:00Z" } ], "brandingHidden": false, "generatedAt": "2026-06-23T10:00:00Z"}days — 90 ячеек, старые первыми. Проценты аптайма — 0..100; значение -1
означает «нет данных» (в том числе avgLatencyMs). У сервиса в окне
обслуживания status: "maintenance" и maintenance: true; overall
принимает значения ok, degraded, down, maintenance, none. Endpoint
публичный: авторизация не нужна, отключённая страница (enabled: false) и
неизвестный slug отвечают 404.
Срез намеренно узкий: внутренние идентификаторы (канала, монитора, самой страницы) и текст ошибки проверки наружу не отдаются — их видно только в админке владельца.
Тарифные ограничения
Заголовок раздела «Тарифные ограничения»| Возможность | Free | Pro | Business |
|---|---|---|---|
| Количество статус-страниц | 1 | 5 | Безлимит |
| Скрыть бейдж «powered by Notifly» | — | ✅ | ✅ |
Превышение лимита страниц вернёт 403 при создании; попытка включить
премиум-поле на неподходящем тарифе — тоже 403 с пояснением в
errorDescription. Актуальные значения лимитов — на странице
Квоты и тарифы.
REST API
Заголовок раздела «REST API»Управление страницами требует API-токен
(X-Notifly-Key) и права владельца канала; изменяющие запросы — токен с правом
write. Публичные endpoints работают без авторизации.
| Метод | Путь | Аутентификация | Описание |
|---|---|---|---|
GET | /status-page | API-токен | Список своих статус-страниц (с охватом views30d) |
POST | /status-page | API-токен (write) | Создать страницу. Body: appid, slug, title, description, enabled, lang, brandingHidden |
PUT | /status-page/{id} | API-токен (write) | Обновить страницу (тот же payload) |
DELETE | /status-page/{id} | API-токен (write) | Удалить страницу |
GET | /status/{slug} | — | Публичная HTML-страница |
GET | /status/{slug}/summary | — | Тот же срез в JSON |
POST | /status/{slug}/subscribe | — | Подписка по email: { "email": "user@example.com" } |
GET | /status-subscribe/verify?token=… | — | Подтверждение подписки (ссылка из письма) |
GET | /status-subscribe/unsub?token=… | — | Отписка (ссылка из письма) |
Коды ответов CRUD: 400 — нет обязательного поля, некорректный slug/язык
или чужой канал, 403 — лимит тарифа или премиум-поле не по плану, 404 —
чужая/несуществующая страница при обновлении, 409 — slug занят. Удаление
отвечает 204.
См. также
Заголовок раздела «См. также»- Активные мониторы — основной источник данных для страницы.
- Heartbeat — «тихие» задачи тоже попадают на страницу.
- Доставка и эскалация — как то же падение доходит до вашей команды, а не до публики.
- Квоты и тарифы — лимиты на количество страниц.