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

HTTP API

Всё, что делает веб-интерфейс, проходит через /api/*, и тот же API открыт для ваших собственных скриптов, дашбордов и ассистентов: закрытой половины нет. Это обычный JSON поверх HTTP с аутентификацией по cookie сессии (веб-интерфейс) или по API-токену (всё остальное).

Каждый экземпляр описывает свой API в документе OpenAPI 3.1:

GET /api/openapi.json

Он публичный — не содержит ни секретов, ни адресов, ни сведений о ваших мониторах — и является исчерпывающим справочником: каждый маршрут, который может вызвать клиент, его параметры, формы запроса и ответа, ответы с ошибками и необходимая область (расширение x-token-scope у каждой операции: public, read, write или none для маршрутов, которые токен не может вызывать никогда). Таблицы ниже на этой странице — удобочитаемая сводка того же самого.

Намеренно исключены: протокол агента (/api/ingest, /api/agent/commands*, /api/agent/relay*), на котором говорит только агент; браузерные перенаправления входа через SSO (/api/auth/oidc/start, /api/auth/oidc/callback) и перенаправление Spotify (/api/music/spotify/callback); а также загрузки агента (/install.sh, /install.ps1, /download/*).

Загрузите его в любой инструмент OpenAPI:

Окно терминала
# Browse it, and try calls with your token, in Swagger UI
docker run --rm -p 8081:8080 \
-e SWAGGER_JSON_URL=http://monit.lan:8080/api/openapi.json swaggerapi/swagger-ui
# then open https://localhost:8081 and paste "dmt_…" under Authorize → bearerAuth
# Generate a client library (here Python)
docker run --rm -v "$PWD:/local" openapitools/openapi-generator-cli generate \
-i http://monit.lan:8080/api/openapi.json -g python -o /local/dumbmonit-client
# Or just list what is there
curl -s http://monit.lan:8080/api/openapi.json | jq -r '.paths | keys[]'

Postman и Insomnia импортируют его по тому же URL.

Два способа входа, принимаются на каждом защищённом маршруте:

  • Cookie сессии — используется веб-интерфейсом. Войдите с паролем (или через SSO) и отправляйте cookie dumbmonit_session с флагом HttpOnly (SameSite Lax; Secure при DUMBMONIT_COOKIE_SECURE=1; 30 дней). Каждый запрос, изменяющий состояние (POST, PUT, DELETE), должен также содержать X-Requested-With: DumbMonit — защиту от CSRF, которую интерфейс добавляет автоматически; без неё запрос отклоняется с кодом 403.
  • API-токен — Authorization: Bearer dmt_…, для скриптов, дашбордов и ассистентов. Создаётся в Settings → API & assistants (те же токены использует MCP-сервер) и показывается один раз. Cookie не участвует, поэтому заголовок X-Requested-With никогда не нужен.
Окно терминала
# API token: one header, nothing else
curl -H 'Authorization: Bearer dmt_…' http://monit.lan:8080/api/targets
curl -H 'Authorization: Bearer dmt_…' -X POST http://monit.lan:8080/api/targets/4/probe
# Session: sign in (204 and a Set-Cookie header), then send the cookie
curl -c cookies.txt -X POST http://monit.lan:8080/api/auth/login \
-H 'content-type: application/json' \
-d '{"username":"admin","password":"…"}'
curl -b cookies.txt http://monit.lan:8080/api/targets
curl -b cookies.txt -X POST http://monit.lan:8080/api/targets \
-H 'X-Requested-With: DumbMonit' -H 'content-type: application/json' \
-d '{"name":"NAS","address":"nas.lan","kind":"snmp","credential":{"type":"snmp_community","community":"public"}}'

Если запрос содержит bearer-токен, cookie игнорируется: отозванный токен отклоняется даже из браузера с выполненным входом, а не незаметно подменяется сессией.

Токены регистрации агентов (dmon_…) — это другое: они работают только на маршрутах агента (/api/ingest, /api/agent/commands/*, /api/agent/relay*). Они говорят о том, что машина может обращаться к серверу, но не о том, какая именно: на этих маршрутах привязанная машина должна дополнительно предъявить собственный секрет привязки в X-DumbMonit-Agent-Secret (dmab_…), который сервер выдаёт один раз при регистрации. См. Привязка.

Вход ограничен по частоте: после пяти неудачных попыток каждая следующая отклоняется с кодом 429 и задержкой Retry-After, которая удваивается от 30 с до 5 минут. Никогда не подбирайте пароли в цикле.

У токена одна из двух областей. Третьей, более мощной, нет: то, что администратор делает от имени своей учётной записи, недоступно ни одному токену.

токен readтокен write
Любой GET, доступный учётной записи viewer (мониторы, оповещения, метрики, правила, каналы без их секретов, страницы статуса…)дада
POST, PUT, DELETE, доступные администратору (мониторы, правила, silences, каналы, страницы статуса, packs, зонды, обнаружение…)403да
/metrics, /federate, /prometheus/* (сбор метрик)дада
Инструменты MCP на чтение / запись (ассистенты)только чтениеоба
Учётные записи, сессии, двухфакторная аутентификация, SSO, журнал аудита (/api/auth/*, /api/users/*)403403
API-токены и токены регистрации агентов (/api/tokens/*, /api/agent/tokens/*)403403
Резервное копирование и восстановление (/api/backup/*)403403

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

  • Показывается один раз, хранится в виде хэша. Токен — это dmt_, за которым следуют 128 случайных бит. Сервер хранит только его дайджест SHA-256 (и первые символы, dmt_1a2b3c4d, чтобы узнавать его в списке); токен в открытом виде существует только в ответе на его создание. Предъявленные токены сравниваются за постоянное время.
  • Срок действия. При создании выберите 30 дней, 90 дней, 1 год или бессрочно. Истёкший токен получает 401 с The API token "<name>" expired on … и WWW-Authenticate: Bearer error="invalid_token"; он остаётся в списке с пометкой «истёк», пока вы его не отзовёте.
  • Разрешённые сети. При желании ограничьте токен списком адресов или диапазонов CIDR (192.168.1.0/24, 10.8.0.5, не более 32 записей). Из любого другого места он получает 403 с The API token "<name>" cannot be used from <address>. Проверяется адрес TCP-клиента или — только если соединение приходит от прокси из DUMBMONIT_TRUSTED_PROXIES — адрес, который этот прокси сообщает в X-Forwarded-For. За необъявленным обратным прокси каждый запрос выглядит как идущий от прокси: объявите его, иначе ограничение отклонит всех.
  • Последнее использование. Список токенов показывает, когда каждый токен использовался в последний раз и с какого адреса (обновляется не чаще раза в минуту или сразу при смене адреса): токен, которым больше никто не пользуется, стоит отозвать.
  • Привязан к создателю. Токен запоминает учётную запись, которая его создала. Если эта учётная запись отключена, её токены отклоняются (401); если её понизили до operator или viewer, её токены write работают как токены read; если она удалена, её токены отзываются.
  • Отзыв мгновенный: следующий вызов получает 401.
  • Журналирование. Каждая запись, выполненная с токеном, попадает в журнал сервера с именем и id токена, методом, путём (без строки запроса) и статусом — но никогда не токен и не тело запроса. Создание и отзыв токена фиксируются в журнале аудита (Settings → Security).

Каждый токен может делать 120 вызовов в минуту, REST и MCP вместе. Сверх этого вызовы отклоняются с кодом 429 и заголовком Retry-After (секунды) до конца минуты. Каждый ответ на запрос с токеном сообщает, где вы находитесь:

ЗаголовокЗначение
RateLimit-LimitДопустимое число вызовов за окно (120).
RateLimit-RemainingСколько вызовов осталось в текущем окне.
RateLimit-ResetСекунд до начала нового окна.

Дашборд Grafana с множеством панелей и коротким интервалом обновления может достичь лимита: выдайте ему отдельный токен или увеличьте интервал обновления.

Страница, загруженная с другого origin, — ваш собственный дашборд, Swagger UI, браузерный MCP-клиент — может вызывать API с bearer-токеном, но никогда с сессией:

  • ответ содержит Access-Control-Allow-Origin только если запрос содержал Authorization: Bearer dmt_… (или для публичного GET /api/openapi.json). Access-Control-Allow-Credentials не отправляется никогда, поэтому браузер никогда не прикладывает cookie сессии к кросс-доменному вызову;
  • preflight (OPTIONS) на /api/* успешен, только если объявленные заголовки включают authorization: 204, методы GET, POST, PUT, DELETE, заголовки authorization, content-type, mcp-protocol-version, mcp-method, mcp-name, кэшируется на 10 минут. X-Requested-With среди них нет, поэтому сессия на cookie никогда не сможет выполнить запись с другого origin;
  • Retry-After, WWW-Authenticate, заголовки RateLimit-* и X-DumbMonit-Api-Version доступны для чтения вызывающему скрипту.

DUMBMONIT_API_CORS_ORIGINS задаёт, какие origin разрешены:

ЗначениеЭффект
не задано (по умолчанию)Любой origin (Access-Control-Allow-Origin: *). Безопасно, поскольку что-либо открывает только bearer-токен.
https://grafana.example.com,https://dash.lanТолько эти origin, возвращаются как есть.
offНикаких заголовков CORS: только страницы с того же origin и не-браузерные клиенты.

Тот же список определяет, какой Origin принимает MCP-эндпоинт.

// From a page on another origin. Never ship a write token in a public page.
const response = await fetch('https://monit.example.com/api/alerts', {
headers: { Authorization: 'Bearer dmt_…' }
});
if (!response.ok) throw new Error((await response.json()).error);
const alerts = await response.json();
console.log(response.headers.get('RateLimit-Remaining'), 'calls left this minute');

Каждый ответ под /api содержит версию API:

X-DumbMonit-Api-Version: 0.1

То же значение — это info.version в документе OpenAPI, рядом с x-server-version, версией сервера, который ответил. Пока API имеет версию 0.x, он не заморожен; версия меняется всякий раз, когда маршрут или поле удаляется либо переименовывается. Добавление маршрута или поля версию не меняет: игнорируйте неизвестные поля.

Каждая ошибка — это JSON: {"error": "message"}, написанный для человека.

СтатусКогда
400Запрос некорректен или значение недопустимо; сообщение называет его.
401Нет действительной сессии или токена: токен отсутствует, неизвестен, отозван или истёк (с WWW-Authenticate: Bearer), либо создатель токена отключён.
403Аутентифицирован, но не разрешено: viewer, operator вне обработки оповещений, токен read на маршруте записи, токен на маршруте учётных записей, токенов или резервных копий, токен, используемый из недопустимой сети, запись по cookie без X-Requested-With или любая запись в публичной демонстрации (с "demo": true).
404Такого id не существует. Путь под /api, не соответствующий ни одному маршруту, отвечает 404 {"error": "Unknown API route: …"}, а не HTML веб-интерфейса.
405Такого метода на этом пути нет (например, GET /api/mcp).
409Конфликт с текущим состоянием (дубликат, уже выполняющаяся команда…).
429Превышен лимит частоты, с Retry-After.
500Сбой сервера; подробности в журнале сервера, но никогда в ответе.
Окно терминала
$ curl -i -H 'Authorization: Bearer dmt_revoked…' http://monit.lan:8080/api/targets
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer
{"error":"A valid API token is required."}
$ curl -i -X DELETE -H 'Authorization: Bearer dmt_…read…' http://monit.lan:8080/api/targets/4
HTTP/1.1 403 Forbidden
{"error":"This action needs a token with the \"write\" scope; the token \"Grafana\" is \"read\" only. Create a write token in Settings → API & assistants."}
$ curl -i -H 'Authorization: Bearer dmt_…' http://monit.lan:8080/api/alerts # the 121st call this minute
HTTP/1.1 429 Too Many Requests
retry-after: 17
ratelimit-limit: 120
ratelimit-remaining: 0
{"error":"Rate limit reached (120 calls per minute per token). Retry in 17 s."}

MCP-эндпоинт отвечает вместо этого в JSON-RPC, со своими кодами ошибок.

В таблицах ниже session означает cookie сессии или API-токен; admin — сессию администратора или токен write; operator — сессию оператора или администратора либо токен write; session only — cookie сессии, но никогда токен.

Роли. Учётная запись viewer выполняет любые GET. operator выполняет те же чтения плюс операции записи по обработке оповещений, помеченные на этой странице как operator (и x-roles: [admin, operator] в документе OpenAPI): подтверждение (acknowledge), откладывание (snooze, окна обслуживания), игнорирование правила для монитора, очистка истории закрытых оповещений. Любая другая запись доступна только администратору и возвращает оператору 403.

МетодМаршрутAuthНазначение
GET/api/auth/statuspublic{"configured": bool, "authenticated": bool, "user": …, "oidc": {"enabled", "provider_name", "login_url"}}. configured: false означает новый экземпляр: пока не существует первого администратора, каждый маршрут с пометкой session отвечает 401 — доступны только status, setup, login и health.
POST/api/auth/setuppublic{"setup_code": "…", "username": "admin", "password": "…"}. Создаёт первого администратора на новом экземпляре (не менее 12 символов); username можно опустить, тогда он равен admin. setup_code — одноразовый код, выводимый в журналы сервера при запуске (или DUMBMONIT_SETUP_CODE); регистр, дефисы и пробелы игнорируются. 204; сессию не открывает. 401 при неверном коде, 429 после слишком многих попыток, 409, когда учётная запись уже существует.
POST/api/auth/loginpublic{"username": "…", "password": "…"}. 204 с Set-Cookie. 401 при неверном пароле, 429 при превышении лимита частоты. Если у учётной записи включена двухфакторная аутентификация, вместо этого 200 с {"totp_required": true, "pending": "…"} — тикет живёт пять минут и аннулируется после пяти неверных кодов: завершите вход через /api/auth/login/totp.
POST/api/auth/login/totppublic{"pending": "…", "code": "123456"} — тикет с первого шага и код (или код восстановления). 204 с cookie сессии.
GET/api/auth/oidc/startpublicПеренаправляет браузер к провайдеру удостоверений.
GET/api/auth/oidc/callbackpublicВозврат от провайдера (code, state): открывает сессию и перенаправляет в интерфейс.
GET/api/auth/mesession onlyТекущая учётная запись: id, username, display_name, role (admin, operator, viewer), auth (password, oidc), disabled, totp_enabled, created_at, last_login_at.
POST/api/auth/logoutsession onlyЗавершает сессию и очищает cookie.
POST/api/auth/passwordsession only{"current_password": "…", "new_password": "…"}. Завершает все остальные сессии.
GET/api/auth/totpsession onlyСостояние двухфакторной аутентификации текущей учётной записи: enabled, pending, recovery_codes_left.
POST/api/auth/totp/enrollsession only{"password": "…"}. Предлагает секрет: secret (base32), otpauth_uri, issuer, account. Ничего не применяется, пока не подтверждено.
POST/api/auth/totp/verifysession only{"code": "123456"}. Подтверждает регистрацию и возвращает {"recovery_codes": […]} — показываются один раз.
DELETE/api/auth/totpsession only{"password": "…"}. Удаляет второй фактор. 204.
GET/api/auth/audit?limit=200admin, session onlyПоследние события безопасности: id, at, actor, action (login, login.failed, password.changed, token.created, user.updated, …), subject, ip.
GET/api/auth/oidc/configadmin, session onlyНастройки SSO и их источник (окружение или база данных); секрет клиента не возвращается никогда.
PUT/api/auth/oidc/configadmin, session only{"issuer", "client_id", "client_secret", "provider_name", "scopes", "auto_create", "admin_groups", "groups_claim", "public_url"}. Отсутствующий или пустой client_secret сохраняет прежний; отсутствующий auto_create означает «выключено».
DELETE/api/auth/oidc/configadmin, session onlyЗабывает сохранённые настройки SSO (переменные окружения, если они есть, снова вступают в силу). 204.
POST/api/auth/oidc/testadmin, session onlyЗагружает discovery-документ провайдера и сообщает, что нашёл.
GET/api/usersadmin, session onlyВсе учётные записи в форме /api/auth/me.
POST/api/usersadmin, session only{"username", "display_name", "role", "password"}. password можно опустить, только если включён SSO. 201.
PUT/api/users/{id}admin, session onlyЛюбое из display_name, role, disabled, password; опущенное поле сохраняет значение. Нельзя понизить или отключить последнего администратора.
DELETE/api/users/{id}admin, session only204. Нельзя удалить себя и последнего администратора.
DELETE/api/users/{id}/totpadmin, session onlyСбрасывает второй фактор другой учётной записи (заблокированный коллега). 204.
GET/api/tokenssession onlyВсе API-токены: id, name, prefix, scope, created_at, created_by (учётная запись, создавшая его), expires_at (null: бессрочный), expired, allowed_networks (пусто: откуда угодно), last_used_at, last_used_ip, revoked_at. Секрет — никогда.
POST/api/tokensadmin, session only{"name": "Grafana", "scope": "read", "expires_in_days": 90, "allowed_networks": ["192.168.1.0/24"]}. name обязательно (не более 80 символов); scope — read (по умолчанию) или write; expires_in_days от 1 до 3650, null или отсутствие — для бессрочного токена; allowed_networks принимает до 32 адресов или диапазонов CIDR, хранится в сетевой форме (192.168.1.7/24 превращается в 192.168.1.0/24), пусто или отсутствует — откуда угодно. 201 с полями токена плюс secret (показывается один раз). 400 указывает недопустимую сеть.
DELETE/api/tokens/{id}admin, session onlyОтзыв. 204; 404, если токен неизвестен или уже отозван.

Токен в списке:

{
"id": 3, "name": "Grafana", "prefix": "dmt_1a2b3c4d", "scope": "read",
"created_at": "2026-10-01T09:12:00Z", "created_by": "admin",
"expires_at": "2026-12-30T09:12:00Z", "expired": false,
"allowed_networks": ["192.168.1.0/24"],
"last_used_at": "2026-10-01T09:30:00Z", "last_used_ip": "192.168.1.20",
"revoked_at": null
}

Помимо X-DumbMonit-Api-Version (версионирование), заголовков RateLimit-* (ограничения частоты) и заголовков CORS (кросс-доменные запросы), каждый ответ содержит X-Content-Type-Options: nosniff, Referrer-Policy: same-origin и Content-Security-Policy. Политика начинается с default-src 'none' и открывает только то, что действительно использует интерфейс — и всё это раздаётся самим DumbMonit:

default-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;
font-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'self';
script-src 'self' 'nonce-<per response>'; frame-ancestors 'none'

Сторонних origin в ней нет и быть не должно: шрифты, библиотека графиков и все ресурсы поставляются внутри бинарного файла. Встроенные скрипты страницы (тема, применяемая до первой отрисовки, начальная загрузка SvelteKit) разрешены nonce, который генерируется заново для каждого ответа, поэтому 'unsafe-inline' к скриптам никогда не применяется. К стилям он применяется и не может быть убран: Svelte устанавливает у элементов атрибуты style=, которые не могут покрыть ни nonce, ни хэш.

Публичные страницы статуса предназначены для встраивания: /s/<slug> и её компактный вид /s/<slug>/embed — и только они — получают ту же политику без frame-ancestors. Всё остальное, включая страницы подтверждения подписки и отписки под /s/, также содержит X-Frame-Options: DENY.

Если вы размещаете DumbMonit за обратным прокси, не позволяйте ему добавлять второй заголовок Content-Security-Policy: браузеры применяют пересечение всех таких политик, а политика прокси по умолчанию без nonce оставляет пустую страницу.

МетодМаршрутAuthНазначение
GET/api/healthpublicВерсия сервера и состояние его зависимостей. Всегда 200: отказавший компонент указан в теле.
GET/api/updatesession или токенЗапущенная версия, последний релиз, update_available; сервер обращается к GitHub не чаще раза в день. POST /api/update/check проверяет сейчас, PUT /api/update/settings включает или выключает проверку. См. Обновление.
{"status":"ok","version":"0.1.0","database":{"ok":true},"victoria":{"ok":true,"embedded":true}}

status равен degraded, когда компонент отказывает; тогда у этого компонента есть строка error. victoria.embedded равен true, когда сервер запускает собственный VictoriaMetrics, и false, когда DUMBMONIT_VM_URL указывает на внешний.

МетодМаршрутAuthНазначение
GET/api/backupadmin, session onlyЧто содержал бы пакет (contents, одна строка на раздел с его количеством), версия формата пакета, где хранится секрет экземпляра (secret_source: file или environment) и состояние локальных резервных копий по расписанию (schedule).
POST/api/backupadmin, session only{"passphrase": "…", "include_account_secrets": false}. Возвращает сам пакет в виде JSON-файла: открытый заголовок (format, version, created_at, summary, kdf) и payload, зашифрованный AES-256-GCM ключом, выведенным из парольной фразы с помощью Argon2id. Не менее 16 символов, иначе 400.
POST/api/backup/restoreadmin, session only{"bundle": {…}, "passphrase": "…", "apply": false}. Пробный запуск, если apply не равно true; оба режима выполняют один и тот же код, пробный — внутри транзакции, которая откатывается. Отвечает отчётом: по разделам created, updated, skipped и notes, плюс warnings. 400 при неверной парольной фразе, изменённом файле или пакете, записанном в более новой версии формата.
POST/api/backup/localadmin, session onlyНемедленно записывает одну локальную копию в стиле плановой и отвечает новым schedule.

Пакет содержит все учётные данные экземпляра, перешифрованные парольной фразой, поэтому эти маршруты отклоняют API-токены с пояснением: доступ получает только администратор, вошедший в веб-интерфейс. См. Резервное копирование и восстановление.

МетодМаршрутНазначение
GET/api/collectorsВсе виды мониторов, которые этот сервер может мониторить: kind, label, summary, examples, credential_types, address_hint, default_port, setup (title, steps, warning, doc_url) и options (key, label, help, placeholder, default, required, input, choices). Виды, добавленные пакетом интеграции, перечисляются так же, как pack.<id>.

Сессия администратора или API-токен (область write для изменений). См. Пакеты интеграций.

МетодМаршрутНазначение
GET/api/packsУстановленные пакеты: id, version, label, summary, kind (null для пакета только с профилями SNMP), enabled, installed_at, sha256, metrics, rules (uid), snmp_profiles, targets (использующие его мониторы), warnings и error, когда сохранённый пакет больше не проходит проверку.
GET/api/packs/{id}Один пакет.
POST/api/packsУстановка или обновление. Тело: YAML (application/yaml, text/plain…) или {"yaml": "…"} в JSON. 201 при создании, 200 при обновлении или отсутствии изменений, с outcome (created, updated, unchanged), pack, rules_added и restart_required (профили SNMP). 400 перечисляет все ошибки проверки.
PUT/api/packs/{id}/enable, /api/packs/{id}/disableЗарегистрировать или отозвать тип монитора пакета; мониторы, история и правила остаются.
DELETE/api/packs/{id}Удаление вместе с его правилами. 409, пока его используют мониторы.
МетодМаршрутНазначение
GET/api/targetsСписок всех мониторов.
POST/api/targetsСоздать одно. 201 с монитором. Для SNMP определение профиля запускается в фоне.
GET/api/targets/{id}Один монитор.
PUT/api/targets/{id}Заменить его. Если опустить credential, сохраняется прежний; если опустить profile_id, сохраняется определённый профиль ("" очищает). Установка enabled: false очищает оповещения монитора без уведомлений.
DELETE/api/targets/{id}204. Очищает оповещения монитора без уведомлений и удаляет его временные ряды из VictoriaMetrics (по возможности).
POST/api/targets/{id}/probeОпросить сейчас: {"sample_count": 42, "series": ["if_octets_in{host=\"Core switch\",ifname=\"eth0\"}", …]} — ключи рядов в том виде, в каком их произвёл коллектор, без префикса dumbmonit_, который записывающий компонент добавляет на пути в VictoriaMetrics.
POST/api/targets/{id}/discoverПовторить определение профиля: {"profile_id": "host-resources"} или null.

Монитор в возвращаемом виде:

{
"id": 4,
"name": "Core switch",
"address": "192.168.1.2",
"kind": "snmp",
"profile_id": "host-resources",
"parent_id": null,
"via_agent": null,
"interval_secs": 60,
"enabled": true,
"tags": {"role": "network"},
"credential_kind": "SNMP community",
"last_probe_at": "2026-09-15 13:20:05",
"last_error": null,
"error_kind": null
}

Сам секрет не возвращается никогда: credential_kind — это метка. Временные метки сервера указаны в UTC без суффикса. error_kind классифицирует last_error: down (монитор не ответил) или config (наша сторона — учётные данные, адрес, параметр); именно это интерфейс показывает как Unreachable или Misconfigured; null, когда последний опрос прошёл успешно.

Создание:

{
"name": "Core switch",
"address": "192.168.1.10",
"kind": "snmp",
"interval_secs": 60,
"parent_id": null,
"tags": {},
"credential": {"type": "snmp_community", "community": "public"}
}

Формы учётных данных (type): none; snmp_community (community); snmp_v3 (username, необязательный auth: {protocol, passphrase} с md5, sha1, sha224, sha256, sha384 или sha512, необязательный privacy: {protocol, passphrase} с des, aes128, aes192 или aes256, необязательный context); api_token (token или две половины token_id и secret, которые сервер объединяет в user@realm!name=secret для Proxmox VE и PBS); username_password (username, password). interval_secs по умолчанию равен 60 и не может быть меньше 10. name — не более 200 символов, address — не более 253 (сверх этого 400). parent_id должен указывать на существующий монитор (400 Parent device N not found.). Параметры типа помещаются в tags под своим ключом.

via_agent называет релейного агента, который опрашивает монитор из своей сети вместо сервера; null (по умолчанию) означает, что опрашивает сервер. Это должен быть монитор agent (иначе 400), монитор не может ретранслировать сам себя, а монитор agent нельзя ретранслировать. При PUT опущенный via_agent сохраняет прежнее значение, как profile_id и credential; отправьте null, чтобы вернуться к прямому опросу. POST /api/targets/{id}/probe и /discover на мониторе за релеем идут через релей и ждут его ответа (409, когда опрос уже выполняется, 400 Timed out: relay agent …, когда он не отвечает).

МетодМаршрутAuthНазначение
POST/api/discoveryadmin{"cidr": "192.168.1.0/24", "community": "public", "port": 161, "timeout_ms": 1000}. Сканирует сеть в поисках SNMP-устройств. cidr обязателен; community по умолчанию public; timeout_ms ограничивается диапазоном 100–10 000. Сети больше 4096 адресов отклоняются. Сканирование — это POST с JSON-телом, чтобы community никогда не появлялся в URL или строке журнала.
{
"scanned": 254,
"devices": [
{"address": "192.168.1.10", "sysname": "sw-core", "sysdescr": "…", "sysobjectid": "1.3.6.1.4.1.8072.3.2.10", "suggested_profile": "host-resources"}
]
}

Три шага, которые обзор показывает на новом экземпляре. Состояние хранится на экземпляре, а не в браузере, поэтому пропуск шага пропускает его везде.

МетодМаршрутAuthНазначение
GET/api/onboardingsessionТекущее состояние экземпляра.
PUT/api/onboardingadmin{"skipped": true} убирает всё руководство; {"dismissed": ["test"]} убирает отдельные шаги. Опущенное поле сохраняет своё значение; id шага, отличный от device, channel или test, — это 400. Возвращает тот же документ, что и GET.
{
"skipped": false,
"complete": false,
"completed_at": null,
"dismissed": [],
"has_target": true,
"has_channel": true,
"notification_confirmed": false
}

has_target, has_channel и notification_confirmed пересчитываются при каждом чтении: это факты об экземпляре, а не флаги, которые устанавливает интерфейс. notification_confirmed становится истинным, когда сообщение действительно ушло через какой-либо канал — тестовое сообщение считается, канал, который только создан, — нет.

complete фиксируется и никогда не возвращается в false. Сервер устанавливает его, когда три шага завершены (выполнены или отклонены), а также при самом первом чтении экземпляра, у которого уже были монитор и канал, — поэтому обновление уже работающего экземпляра никогда не показывает ему руководство первого запуска.

Оба маршрута проксируют VictoriaMetrics и возвращают ряды в форме Prometheus: [{"metric": {labels…}, "values": [[timestamp_seconds, "value"], …]}].

МетодМаршрутНазначение
GET/api/metrics/query?query=…Мгновенный запрос MetricsQL.
GET/api/metrics/query_range?query=…&start=…&end=…&step=…Запрос диапазона. start и end — миллисекунды с начала эпохи; step в секундах и увеличивается так, чтобы ряд никогда не превышал 2000 точек.
Окно терминала
curl -b cookies.txt -G https://localhost:8080/api/metrics/query \
--data-urlencode 'query=avg by (target, host) (dumbmonit_cpu_usage_percent)'
[{"metric":{"host":"ThinkpadE14","target":"3"},"values":[[1757941205,"12.5"]]}]

Для существующего Prometheus или Grafana. Оба принимают API-токен read в Authorization: Bearer dmt_… (cookie сессии тоже работает); сборщик не отправляет заголовок X-Requested-With и не нуждается в нём — эти маршруты только читают. См. справочник метрик с готовым для копирования scrape_config и источником данных Grafana.

МетодМаршрутНазначение
GET/metricsСостояние самого экземпляра в текстовом формате экспозиции Prometheus: планировщик, опросы, записи, оповещения, уведомления, агенты, база данных, VictoriaMetrics. Несколько десятков рядов, никогда по одному на монитор.
GET/federateИзмерения в том же формате. match[] выбирает ряды (повторяемый, не более 10, по умолчанию {__name__=~"dumbmonit_.*"}), max_lookback расширяет окно, в котором ищется последняя точка (по умолчанию 5m). 400 сверх 8 MiB, с указанием, что сузить.
GET, POST/prometheus/api/v1/{route}Читающая половина API Prometheus, ретранслируемая в хранилище, чтобы Grafana могла использовать http://…/prometheus как источник данных Prometheus. Только query, query_range, query_exemplars, series, labels, label/{name}/values, metadata и status/buildinfo; всё остальное — 404.

DUMBMONIT_METRICS_PUBLIC=true отдаёт все три без токена — только за брандмауэром, поскольку они содержат каждое измерение каждого монитора.

Маршруты, не описанные выше; документ OpenAPI приводит их параметры и формы ответов. read и write — необходимая область токена; none означает, что токен не принимается (только сессия).

МетодМаршрутОбластьНазначение
POST/api/targets/reorderwriteИзменить порядок мониторов.
GET/api/targets/{id}/securityreadОценка безопасности, класс и проверки одного монитора.
GET/api/security/summaryreadОценка безопасности каждого оценённого монитора, худшие первыми.
GET/api/targets/{id}/webchange/pagesreadСтраницы, отслеживаемые наблюдением за сайтом.
GET/api/targets/{id}/webchange/changesreadИзменения, найденные на отслеживаемом сайте, сначала новые.
GET/api/targets/{id}/webchange/changes/{change_id}readОдно изменение с обеими версиями и построчным diff.
GET/api/targets/{id}/webchange/snapshots/{snapshot_id}/screenshotreadСкриншот снимка.
POST/api/targets/{id}/webchange/checkwriteПроверить отслеживаемый сайт сейчас.
GET/api/targets/{id}/opnsense/gateways, /traffic, /healthreadOPNsense: шлюзы и WAN-адреса; интерфейсы, межсетевой экран и DHCP; система, службы, туннели и прошивка.
GET/api/targets/{id}/truenas/storage, /protection, /healthreadTrueNAS: пулы, датасеты и диски; scrub и задачи защиты данных; система, оповещения и службы.
GET/api/targets/{id}/ad, /ad/findingsreadActive Directory: домен, контроллеры, привилегированные группы и находки; необработанные находки безопасности.
GET/api/targets/{id}/redfishreadАппаратное состояние сервера, прочитанное с его контроллера управления.
GET/api/targets/{id}/observabilityreadСостояние сервера логов или метрик.
GET/api/targets/{id}/backendreadСостояние Redis, MongoDB, RabbitMQ или CrowdSec.
GET/api/targets/{id}/proxyreadСостояние обратного прокси или регистрации домена.
GET/api/public/status/{slug}/badge.svg, /response.svg, /uptime.svgpublicБейджи общего статуса, среднего времени отклика и аптайма страницы статуса.
GET/api/public/status/{slug}/components/{key}/badge.svg, /uptime.svg, /response.svgpublicТе же бейджи для одного сервиса страницы.
GET/api/public/status/{slug}/banner.jspublicСкрипт баннера статуса для сторонних сайтов.
GET/api/public/status/{slug}/rsspublicИнциденты в виде RSS-ленты.
GET/api/music/nowreadЧто играет на экранах (монитор комнаты).
PUT, DELETE/api/music/linkwriteВсе экраны воспроизводят эту ссылку Spotify, Deezer или YouTube; либо останавливают встроенный плеер.
GET, DELETE/api/music/spotifyread, writeПодключённая учётная запись Spotify (никогда не токен); отключить её и забыть её токены.
POST/api/music/spotify/authorize, /completenoneНачать подключение Spotify; завершить loopback-подключение. Только сессия.
GET/api/music/spotify/tokennoneКраткоживущий токен доступа Spotify для плеера экрана. Только сессия.
GET, PUT/api/music/speakerread, writeКолонка Spotify экрана в том виде, как её показывает Settings; переименовать её (admin).
POST/api/music/speaker/report, /playnoneЭкран сообщает состояние своей колонки; воспроизвести на ней учётную запись. Только сессия.
POST/api/music/spotify/playbacknoneПоставить на паузу или возобновить учётную запись с экрана, где бы она ни играла. Только сессия.
МетодМаршрутНазначение
GET/api/alertsАктивные оповещения (pending, firing, suppressed, недавно закрытые). Оповещения удалённых или приостановленных мониторов не перечисляются никогда.
GET/api/alerts/history?since=2026-09-01T00:00:00Z&limit=200&dismissed=falseПереходы между фазами. since — RFC 3339, по умолчанию последние семь дней; limit должен быть положительным. dismissed (по умолчанию false) исключает записи, очищенные двумя маршрутами ниже; очистка ничего не уничтожает, а лишь скрывает из вида по умолчанию.
POST/api/alerts/history/{id}/dismissУбирает одну запись resolved из вида истории по умолчанию. 204. 404 для неизвестного id или ещё активного перехода. Operator; попадает в аудит.
POST/api/alerts/history/dismiss-resolvedУбирает сразу все ещё не очищенные записи resolved («Clear all resolved»). Возвращает {"dismissed": <count>}. Operator; попадает в аудит.
POST/api/alerts/{fingerprint}/ackПодтверждение: {"duration_secs": 14400, "note": "…"} или {"until": "2026-09-22T18:00:00Z"} (одно из двух; если ни одного — 4 часа, максимум 30 дней). {"until": null} снимает его. Возвращает оповещение. Operator; попадает в аудит.
DELETE/api/alerts/{fingerprint}/ackСнять подтверждение. Возвращает оповещение. Operator.

Активное оповещение:

{
"fingerprint": "…",
"rule_uid": "disk_almost_full",
"rule_name": "Disk almost full",
"severity": "warning",
"target_id": 4,
"series_key": "…",
"labels": {"host": "Core switch", "mountpoint": "/", "target": "4"},
"phase": "firing",
"effective_phase": "suppressed",
"suppressed": true,
"suppressed_by": 2,
"silenced": false,
"learning": false,
"acked": true,
"acked_until": "2026-09-15T17:20:00Z",
"acked_by": "admin",
"ack_note": "replacing the disk",
"value": 95.96,
"score": null,
"condition_since": "2026-09-15T12:00:00Z",
"firing_since": "2026-09-15T12:15:00Z",
"last_eval_at": "2026-09-15T13:20:00Z",
"last_notified_at": null,
"notify_count": 0
}

Запись истории содержит id, fingerprint, rule_uid, target_id, from_phase, to_phase, severity, value, notified, reason (пусто или причина, по которой ничего не было отправлено: learning: would have fired, suppressed: device 2 unreachable, maintenance window, acknowledged by admin, device removed or disabled), at и dismissed (убрано из активного вида; сама строка сохраняется). acked истинно, пока acked_until находится в будущем: напоминания и эскалации приостанавливаются, закрытие всё равно уведомляется и снимает подтверждение. target_id, которого больше не существует, интерфейс показывает как «(deleted device)».

МетодМаршрутНазначение
GET/api/alerts/rulesВсе правила.
POST/api/alerts/rulesСоздать. 201.
PUT/api/alerts/rules/{id}Обновить. Встроенное правило сохраняет свой запрос.
DELETE/api/alerts/rules/{id}204. Встроенные правила удалить нельзя.
POST/api/alerts/rules/{id}/enable{"enabled": false}. Возвращает правило.

Правило:

{
"id": 2, "uid": "cpu_high", "name": "High CPU",
"description": "CPU load sustained above 90%.",
"kind": "threshold",
"query": "avg by (target, host) (dumbmonit_cpu_load_percent or dumbmonit_proxmox_node_cpu_percent or dumbmonit_cpu_usage_percent)",
"operator": ">", "threshold": 90, "for_secs": 600,
"severity": "warning",
"selector": {"kind": "all"},
"channels": [],
"params": {"k": 3.5, "alpha": 0.05, "mad_floor_abs": 1e-6, "mad_floor_rel": 0.01, "min_samples": 3},
"unit": "%", "repeat_secs": 21600, "escalate_after_secs": 3600,
"enabled": true, "builtin": true
}

Для создания нужны как минимум name и query; kind (threshold, anomaly, predict), operator, threshold, for_secs, severity (info, warning, critical), selector ({"kind":"all"}, {"kind":"ids","ids":[…]} или {"kind":"labels","labels":{…}}), channels (id каналов; пусто означает все включённые каналы), unit, repeat_secs, escalate_after_secs и enabled необязательны.

МетодМаршрутНазначение
GET/api/alerts/silencesВсе окна, с active_now, active_until и next_start_at (RFC 3339, вычисляются сервером).
POST/api/alerts/silencesСоздать. 201. Operator.
DELETE/api/alerts/silences/{id}204. Operator.
{
"name": "Sunday backups",
"comment": "NAS is busy",
"target_id": 4,
"matchers": {},
"schedule": {"kind": "weekly", "days": [6], "start_minute": 120, "end_minute": 240, "timezone": "Europe/Paris"},
"enabled": true
}

Разовое расписание — {"kind": "once", "starts_at": "2026-09-20T22:00:00Z", "ends_at": "2026-09-21T02:00:00Z"}. Ежемесячное — {"kind": "monthly", "days": [1], "nth_weekdays": [{"nth": 1, "weekday": 6}], "start_minute": 120, "duration_minutes": 120, "timezone": "Europe/Paris"} — nth от 1 до 5 или -1 для последнего в месяце; месяц без такого вхождения пропускается. Дни: 0 = понедельник … 6 = воскресенье (1–31 для days ежемесячного расписания); минуты отсчитываются от местной полуночи (0–1439). В повторяющемся расписании timezone (имя IANA) главнее utc_offset_minutes и сохраняет окно на его местном часе при переходе на летнее/зимнее время; неизвестное имя зоны отклоняется.

Правило можно настроить для одного монитора, не меняя само правило. {"enabled": false} — это то, что записывает действие Ignore интерфейса (на оповещении, странице монитора или правиле): монитор исключается из этого одного правила насовсем, но обратимо, без отключения правила для всех остальных.

МетодМаршрутНазначение
GET/api/alerts/overrides?target_id=4Все переопределения или переопределения одного монитора: rule_uid, target_id, threshold, clear_threshold, enabled.
GET/api/alerts/rules/{id}/overridesПереопределения одного правила.
PUT/api/alerts/rules/{id}/overrides/{target_id}{"threshold": 95, "clear_threshold": 90, "enabled": true} — каждое поле необязательно; null означает «как в правиле». Создаёт или заменяет. Operator может отправлять только {"enabled": false} (ignore); пороговые переопределения монитора, если они есть, сохраняются.
DELETE/api/alerts/rules/{id}/overrides/{target_id}204. Для operator только снимает ignore: пороговые переопределения остаются.
GET/api/targets/{id}/rulesThe rules that watch a device: those whose query reads a metric it wrote in the last 24 h. {"status": "ok" | "no_data" | "unavailable", "rules": [{id, uid, name, description, severity, enabled, ignored, custom_threshold, firing}]}.
МетодМаршрутНазначение
GET/api/notify/policyГлобальная политика: batch_window_secs (0 = отправлять сразу), max_per_hour на канал (0 = без ограничений), flap_events, flap_window_secs, flap_hold_secs (0 = без обнаружения флаппинга), public_url (ссылки в сообщениях; пусто = DUMBMONIT_PUBLIC_URL), escalate_after_secs и escalate_channel (0 / null = без эскалации).
PUT/api/notify/policyТе же поля, каждое необязательно: опущенное поле сохраняет значение. "escalate_channel": null отключает эскалацию. Возвращает политику.
POST/api/notify/match-preview{"matcher": {…}} → какие мониторы выбирает фильтр маршрутизации канала: devices (id, name, kind, tags, matched), matched, total, rules, excluded_rules.
МетодМаршрутНазначение
GET/api/notify/kindsВсе типы каналов с их полями settings и secrets (key, label, required, input, help, placeholder, options, shape, default) и doc_url, например https://dumbmonit.readthedocs.io/en/latest/notifications/#discord.
GET/api/notify/channelsВсе каналы: id, name, kind, enabled, settings, has_secret, last_error, last_sent_at, policy (min_severity, notify_resolved, min_interval_secs, quiet_hours, matcher). Секреты не возвращаются никогда.
POST/api/notify/channelsСоздать. 201.
PUT/api/notify/channels/{id}Обновить. Если опустить secrets, сохраняются прежние; "secrets": {} очищает их. В policy отсутствие matcher сохраняет фильтр маршрутизации, а "matcher": null очищает его.
DELETE/api/notify/channels/{id}204.
POST/api/notify/channels/{id}/testОтправить тестовое сообщение: {"ok": true, "message": "…"}.
{
"name": "Ops Discord",
"kind": "discord",
"enabled": true,
"settings": {"username": "DumbMonit"},
"secrets": {"webhook_url": "https://discord.com/api/webhooks/…"}
}

Точные ключи для каждого вида берутся из /api/notify/kinds и описаны в Каналы уведомлений.

Устройства текущей учётной записи (только сессия, включая viewer; API-токены получают 401). Канал webpush отправляет на них; см. Push-уведомления (PWA).

МетодМаршрутНазначение
GET/api/webpush{"public_key": "…", "devices": […]}: публичный ключ VAPID (base64url, applicationServerKey для подписки) и устройства учётной записи — id, device (Firefox on Android), push_service (хост), fingerprint (первые 16 шестнадцатеричных символов SHA-256 от endpoint), created_at, last_success_at, last_error. Endpoint, ключи браузера и закрытый ключ не возвращаются никогда.
POST/api/webpush/subscriptionsPushSubscription.toJSON(): {"endpoint": "https://…", "keys": {"p256dh": "…", "auth": "…"}}. 201 с устройством. Endpoint должен быть HTTPS на публичном адресе: частные, loopback и link-local адреса получают 400. Тот же endpoint повторно заменяет свою строку.
DELETE/api/webpush/subscriptions/{id}204; 404 для устройства другой учётной записи.
POST/api/webpush/test{} или {"id": 3}. Отправляет тестовое уведомление: {"ok", "delivered", "failed", "removed", "message"}. Подписки, ответившие 404/410, удаляются.

Только администраторы, включая GET (ответ содержит список получателей). Bearer-токенам для изменений нужна область write. См. Отчёты по email.

МетодМаршрутAuthНазначение
GET/api/reports/schedulesadminВсе отчёты: id, name, enabled, frequency, weekday (0 — понедельник), day_of_month, hour, timezone, recipients, channel_id, last_sent_at, last_error, next_run_at.
POST/api/reports/schedulesadminТе же записываемые поля; по умолчанию каждое — еженедельно, понедельник, 8:00, UTC. recipients содержит не более 20 адресов и обязательно, чтобы включить отчёт; channel_id должен быть каналом smtp или null. 201; 409 сверх 10 отчётов.
GET/api/reports/schedules/{id}adminОдин отчёт.
PUT/api/reports/schedules/{id}adminПолная замена.
DELETE/api/reports/schedules/{id}admin204.
POST/api/reports/schedules/{id}/send-testadminОтправляет предпросмотр по email сохранённым получателям: {"sent": 2, "failed": 0}. Расписание не затрагивает. 400 без пригодного email-канала; 409 в течение 30 секунд после предыдущего предпросмотра.
МетодМаршрутAuthНазначение
GET/api/status-pagessessionВсе страницы с их элементами: page (id, slug, title, description, published, theme, show_uptime_days, created_at, updated_at) и items (id, page_id, target_id, label, group_name, position).
POST/api/status-pagesadmin{"title", "slug", "description", "published", "theme", "show_uptime_days"}. title обязателен (не более 120 символов); slug (^[a-z0-9-]{2,40}$) выводится из заголовка, если опущен; theme — auto (по умолчанию), light или dark; show_uptime_days от 7 до 90 (по умолчанию 90). 201; 409, если slug уже занят.
GET/api/status-pages/{id}sessionОдна страница с её элементами.
PUT/api/status-pages/{id}adminТе же поля, но это полная замена, а не патч: title обязателен, и каждое опущенное поле возвращается к значению по умолчанию (slug выводится заново из заголовка, пустое описание, published: false, theme: auto, 90 дней аптайма).
DELETE/api/status-pages/{id}admin204. Публичный URL перестаёт отвечать.
POST, PUT/api/status-pages, /api/status-pages/{id} — внешний вид и подпискиadminТакже принимают accent (default, blue, teal, violet, rose, amber), scenes (id сцен: paris, tokyo, newyork, dubai, без дубликатов; удалённый id вроде venice или matterhorn сводится к ближайшему из четырёх; [] — ни одной; если опущено при создании: ["paris"]), simple (boolean, по умолчанию false: публичная страница не показывает сцену, талисман и анимацию и следует светлой/тёмной теме посетителя), scene_rotation (visit, 1m, 10m или 1h), footer_text (простой текст, 280 символов), homepage_url (http(s):// или пусто), subscribe_channel_id (канал smtp или null, чтобы выключить подписку по email) и domain (публичное имя хоста страницы, например status.example.com, или null/"", если его нет — см. Собственный домен). domain приводится к нижнему регистру и теряет префикс https:// или завершающий слеш; порт, путь или IP-адрес — это 400, адрес самого DumbMonit (его публичный URL или хост, на который пришёл запрос) — 400, а имя, которое использует другая страница, — 409. В отличие от остальных полей, эти восемь сохраняют своё значение, если опущены в PUT. Вид страницы возвращает их вместе с logo_type (image/png, image/jpeg, image/webp или null).
GET, PUT, DELETE/api/status-pages/{id}/logosession / adminЛоготип страницы. PUT принимает {"data": "<base64 или data: URL>"}: PNG, JPEG или WebP, определяемые по содержимому, не более 256 KiB, всё остальное — 400. 204. GET — предпросмотр редактора (включая черновики).
GET/api/status-pages/{id}/subscriberssessionПодписчики по email: id, page_id, email, confirmed_at (null, пока ожидает), created_at. Их токены никогда не покидают сервер.
DELETE/api/status-pages/{id}/subscribers/{subscriber}adminУдаляет адрес. 204.
PUT/api/status-pages/{id}/itemsadmin[{"target_id": 4, "label": "NAS", "group_name": "Storage"}, …] — полный упорядоченный список мониторов, показываемых на странице.
GET/api/incidentssessionВсе инциденты с их обновлениями: incident (id, page_id, title, kind, status, severity, starts_at, ends_at, created_at, updated_at) и updates.
POST/api/incidentsadmin{"title", "kind", "status", "severity", "page_id", "starts_at", "ends_at", "body"} — body — первое обновление. 201.
PUT/api/incidents/{id}adminТе же поля; опущенное поле сохраняет значение.
DELETE/api/incidents/{id}admin204.
GET/api/incidents/{id}/updatessessionХронология: id, incident_id, status, body, created_at.
POST/api/incidents/{id}/updatesadmin{"status": "monitoring", "body": "…"}. Добавляет обновление и переводит инцидент в status. 201.
GET/api/public/status/{slug}publicJSON-документ, из которого строится опубликованная страница (также badge.svg и rss по тому же пути). В page show_uptime_days — настроенный максимум, history_days — реально показываемое окно (возраст данных страницы, от 7 дней до этого максимума), а simple отражает простой режим. См. Страницы статуса. На собственном домене страницы (Host равен её domain) отвечают только маршруты /api/public/status/{slug}/… этой страницы; любой другой маршрут этого справочника там даёт 404.
GET/api/public/status/{slug}/uptime.svg, /response.svgpublicБейджи страницы: средний аптайм за ?days= 1, 7, 30 (по умолчанию) или 90 — 400 за пределами истории страницы — и среднее время отклика. SVG, Cache-Control: public, max-age=60.
GET/api/public/status/{slug}/components/{key}/badge.svg, /uptime.svg, /response.svgpublicТе же три бейджа для одного сервиса; key — это key сервиса в публичном документе (его метка в виде для URL). 404 для неизвестного ключа.
GET/api/public/status/{slug}/logopublicЛоготип страницы с типом изображения, кэшируется на сутки (logo_url документа содержит версию). 404, если логотипа нет.
POST/api/public/status/{slug}/subscribepublic{"email": "…"}. Отправляет ссылку подтверждения через SMTP-канал страницы. Всегда 202 с одним и тем же сообщением, каково бы ни было состояние адреса; 400 для недопустимого адреса; 404, когда страница не предлагает подписку по email; 409, когда страница не может принять больше подписчиков; 429 с Retry-After сверх пяти запросов на клиента и шестидесяти в целом за 15 минут.
POST/api/public/status/{slug}/confirm?token=…publicПодтверждает подписку (ссылка из письма подтверждения открывает /s/{slug}/confirm, кнопка которой отправляет POST сюда). 404 для неизвестного или истёкшего токена.
POST/api/public/status/{slug}/unsubscribe?token=…publicУдаляет подписку; тело игнорируется, поэтому это также цель one-click по RFC 8058 для List-Unsubscribe. Всегда 200.
МетодМаршрутAuthНазначение
GET/api/agent/tokenssession onlyВсе токены: id, name, prefix, created_at, last_used_at, revoked_at, max_uses (null для токена флота), uses, expires_at.
POST/api/agent/tokensadmin, session only{"name": "Home fleet", "base_url": "https://server:8080", "reusable": false, "max_uses": null, "expires_in_days": null}. 201 с полями токена плюс secret (показывается один раз), install_linux и install_windows. base_url — URL, которым будут пользоваться агенты; по умолчанию — адрес прослушивания. Без reusable токен одноразовый: он регистрирует одну машину и не более. С ним max_uses ограничивает число регистраций (null: без ограничений). expires_in_days прекращает регистрации через указанное число дней; уже зарегистрированные машины продолжают отправлять данные. 400 для значения меньше 1.
DELETE/api/agent/tokens/{id}admin, session onlyОтзыв. 204; 404, если токен неизвестен или уже отозван.
POST/api/ingestAuthorization: Bearer dmon_… + X-DumbMonit-Agent-SecretПринимает пакет образцов от агента (тела до 16 МБ). Не предназначен для ручного вызова. Заголовок несёт секрет привязки машины; агент, у которого его нет, опускает его — так он и запрашивает секрет. Ответ добавляет agent_secret (секрет, возвращается ровно один раз, когда машина привязана) и bound. 403, когда машина привязана к другой установке агента или когда токен больше не может регистрировать — сообщение говорит, что именно и что делать.
GET/api/agent/relay?wait=NAuthorization: Bearer dmon_… + X-DumbMonit-Agent-Key + X-DumbMonit-Agent-SecretОпросы, делегированные релейному агенту (relay: true). Удерживается до wait секунд (максимум 25), когда ничего не ожидает. Каждый элемент — команда вида probe, чьи args содержат цель, её расшифрованные учётные данные, timeout_secs и discover. Никогда не записывается на диск.
POST/api/agent/relay/{id}Authorization: Bearer dmon_… + X-DumbMonit-Agent-Key + X-DumbMonit-Agent-SecretРезультат делегированного опроса: {"duration_ms", "error", "samples", "profile_id"} (тела до 16 МБ). 204; 404, когда опрос истёк или принадлежит другому агенту.
GET/api/agent/commands?wait=NAuthorization: Bearer dmon_… + X-DumbMonit-Agent-Key + X-DumbMonit-Agent-SecretКоманды, поставленные в очередь для агента (перезапуск или обновление контейнера), удерживается до wait секунд, когда ничего не ожидает. Не предназначен для ручного вызова. Один key ничего не доказывает — он публичен, — поэтому привязанная машина должна также предъявить свой секрет привязки; иначе 403, что и мешает одной машине забирать команды другой.
POST/api/agent/commands/{id}Authorization: Bearer dmon_… + X-DumbMonit-Agent-Key + X-DumbMonit-Agent-SecretХод выполнения и результат команды, сообщаемые агентом. result усекается до последних 4 КБ, и в таком случае в начало добавляется [truncated by the server, beginning dropped].
GET/api/relayssessionВсе мониторы-агенты как возможные релеи: id, name, site, relay (объявлено relay: true), last_seen_at, relayed (мониторы, доступные через него), gateway_wanted, gateway_port, gateway_host (его шлюз для агентов его площадки), client_id. Сначала релеи, затем по имени.
GET/api/relays/kindssessionТипы, которые может опрашивать агент-ретранслятор; формы предлагают Доступен через только для них.
{
"id": 1, "name": "Home fleet", "prefix": "dmon_ab12",
"created_at": "2026-09-15 13:00:00", "last_used_at": null, "revoked_at": null,
"secret": "dmon_…",
"install_linux": "curl -sSL https://server:8080/install.sh | sh -s -- --token=dmon_… --url=https://server:8080",
"install_windows": "& ([scriptblock]::Create((irm https://server:8080/install.ps1))) -Token dmon_… -Url https://server:8080"
}

Действия над контейнерами машины, на которой работает агент. Каждый маршрут отвечает 404, если монитор не является целью agent.

МетодМаршрутНазначение
GET/api/targets/{id}/agentМашина в том виде, как её последний раз описал агент: hostname, os, os_version, arch, agent_version, commands_supported, relay, site, relayed (мониторы, доступные через этого агента), last_seen_at, binding, bound, bound_at, rebind_until. 404, пока агент ничего не сообщил. commands_supported равно true только когда агент заявил, что получает команды (commands: true, значение по умолчанию у текущих агентов); более старый агент или агент с commands: false даёт false. binding — bound, pending (бинарный файл может быть привязан и будет привязан со следующим пакетом) или unsupported (агент старше привязки: переустановите его).
POST/api/targets/{id}/agent/rebindAdmin. Открывает часовое окно, в течение которого эта машина может привязаться заново с действительным токеном регистрации — путь назад после переустановки, унёсшей секрет агента. {"rebind_until", "minutes"}. Окно закрывается, как только оно использовано, а старый секрет перестаёт работать. 404, пока агент ничего не сообщил.
GET/api/targets/{id}/containersВсе контейнеры из последнего пакета: name, image, up, health, restart_count, uptime_seconds, image_age_seconds, update_available, policy, last_command.
PUT/api/targets/{id}/containers/{name}/policy{"auto_restart": bool, "auto_update": bool, "prune_old_image": bool, "only_in_maintenance": bool}. Каждое поле необязательно: опущенное поле сохраняет своё значение. Возвращает полную политику.
POST/api/targets/{id}/containers/{name}/restartПоставить перезапуск в очередь. 201 с командой. 404, когда name нет в инвентаре агента; 409, когда такая же команда уже в очереди или выполняется либо когда агент не может выполнять команды (см. commands_supported).
POST/api/targets/{id}/containers/{name}/updateПоставить обновление в очередь; необязательно {"prune": bool} (по умолчанию — из политики). Те же коды статуса, что и у перезапуска.
GET/api/targets/{id}/commandsПоследние 20 команд, сначала новые: id, kind (container.restart, container.update), args, status, requested_by (пользователь или policy), created_at, started_at, finished_at, result.
DELETE/api/targets/{id}/commands/{command_id}Отменить команду в очереди. 204; 409, как только агент её забрал или когда она уже закрыта; 404, когда она не принадлежит этому монитору.

status проходит queued → running → done | failed. Существуют ещё два конечных состояния: cancelled (человек отозвал команду) и expired (сервер сдался через десять минут, потому что ни один агент не пришёл за ней — агент остановлен, слишком стар для канала команд или установлен с commands: false). Сервер сам каждую минуту помечает устаревшие команды как просроченные; команда в очереди никогда не блокирует новую дольше этого срока.

Строки панели Guests монитора Proxmox VE, собранные из последнего опроса в хранилище метрик (четыре мгновенных запроса, у гипервизора ничего не запрашивается). 404, когда монитора не существует, 400, когда он не является целью proxmox.

МетодМаршрутНазначение
GET/api/targets/{id}/proxmox/guestsОдин объект на ВМ или контейнер, отсортированы по узлу, затем по VMID: vmid, name, node, kind (qemu, lxc), status (running, stopped, paused, suspended, template, unknown), cpu_percent (от выделенных ядер), cpu_count, memory_used_bytes, memory_total_bytes, memory_percent, balloon_bytes, disk_used_bytes, disk_total_bytes, disk_percent, agent (true — агент гостя ответил, false — включён, но молчит, null — нет), network_in_bps, network_out_bps, disk_read_bps, disk_write_bps, uptime_seconds, last_backup_age_seconds, ha_state, pool (его пул ресурсов), lock (только пока удерживается блокировка: backup, migrate…), os и ip (видимые изнутри гостя, обновляются раз в час). Каждое неизвестное значение — null: у ВМ без агента гостя есть disk_total_bytes, но disk_used_bytes: null; остановленный гость сохраняет свои размеры и теряет измерения.
[
{
"vmid": 202, "name": "nextcloud", "node": "pve2", "kind": "lxc", "status": "running",
"cpu_percent": 1.0, "cpu_count": 4,
"memory_used_bytes": 1879048192, "memory_total_bytes": 4294967296, "memory_percent": 43.75, "balloon_bytes": null,
"disk_used_bytes": 61203283968, "disk_total_bytes": 107374182400, "disk_percent": 57.0, "agent": null,
"network_in_bps": 1024.0, "network_out_bps": 512.0, "disk_read_bps": 0.0, "disk_write_bps": 2048.0,
"uptime_seconds": 3196800, "last_backup_age_seconds": 25200, "ha_state": "started",
"pool": "production", "lock": null,
"os": "Debian GNU/Linux 12 (bookworm)", "ip": "192.168.10.60"
}
]

Разделы Nodes и Ceph той же страницы монитора, прочитанные из того же последнего опроса. Те же коды статуса, что и выше.

МетодМаршрутНазначение
GET/api/targets/{id}/proxmox/nodes{"nodes": […], "fencing_state", "fencing_armed"} — состояние HA-watchdog (armed, standby…) и то, действительно ли он изолировал бы потерянный узел, затем по одному объекту на узел, отсортированы по имени: name, up, cpu_percent, cpu_iowait_percent, memory_percent, ksm_shared_bytes, rootfs_percent, uptime_seconds, version (релиз pve-manager, установленный на этом узле), services_down (имена юнитов остановленных или упавших демонов), interfaces_offline (интерфейсы, которые должны подниматься при загрузке, но не подняты), thin_pools (name, vg, used_percent, metadata_used_percent, size_bytes) и volume_groups (name, used_percent, size_bytes). Узел, переставший отвечать, сохраняет свою запись с up: false.
GET/api/targets/{id}/proxmox/cephavailable (false, когда в кластере нет Ceph — тогда интерфейс вообще не рисует раздел), health (0 OK, 1 WARN, 2 ERR, 3 неизвестно), health_status, bytes_used, bytes_total, used_percent, osds_total, osds_up, osds_in, osds (name, host, device_class, up, in, used_percent, used_bytes, total_bytes, apply_latency_ms, commit_latency_ms), pools (name, used_percent, used_bytes, size, min_size, pg_num, pg_num_optimal, autoscale), filesystems (имена CephFS), flags (установленные в данный момент флаги OSD, например noout) и muted_checks (заглушённые проверки здоровья, которые HEALTH_OK больше не упоминает).

Панели монитора pbs, прочитанные из последнего опроса (у сервера ничего не запрашивается, кроме журнала задач). 404, когда монитора не существует, 400, когда он не является целью pbs.

МетодМаршрутНазначение
GET/api/targets/{id}/pbs/calendar?days=30&offset=120{"probed_at", "days", "offset_minutes", "groups": […]}: по одной записи на группу резервного копирования (datastore, namespace, backup_type, backup_id, name, count, last_time, last_size, last_verified, last_success, last_failure, retention) с массивом days из {date, state, runs, snapshot}. offset — смещение UTC наблюдателя в минутах, чтобы дни разделялись по местной полуночи.
GET/api/targets/{id}/pbs/failures?days=30Неудавшиеся задачи: upid, worker_type, kind, worker_id, datastore, start, end, error.
GET/api/targets/{id}/pbs/jobs{"probed_at", "jobs": […]}: задания sync, verify, prune и garbage-collection с их расписанием и последним результатом.
GET/api/targets/{id}/pbs/healthХранилища данных (использование, ожидаемая дата заполнения), диски (SMART, износ) и пулы ZFS.
GET/api/targets/{id}/pbs/tasks/{upid}/log?lines=200Журнал одной задачи, получаемый с сервера: {"upid", "lines": […]}; lines ограничивает число возвращаемых строк.
GET/api/targets/{id}/pbs/disks/smart?disk=/dev/sdaАтрибуты SMART одного диска; disk обязателен (без него 400).
GET/api/targets/{id}/pdm/remotesProxmox Datacenter Manager: итоги по всему парку (estate) и по строке на каждый федеративный экземпляр (id, kind, reachable, error, version, version_behind, количества узлов и гостей, память и хранилище, subscription, last_collection, tasks_failed), недоступные первыми.
GET/api/targets/{id}/pdm/failures?days=14Задачи, завершившиеся неудачей по всему парку: upid, remote, worker_type, kind, worker_id, node, start, end, error.
GET/api/targets/{id}/pdm/healthХост консоли: CPU, память, корневая файловая система, аптайм, сертификаты, ожидающие обновления и подписка.
GET/api/targets/{id}/pmg/queuesProxmox Mail Gateway: четыре очереди Postfix в порядке чтения (queue, messages, domains, oldest_age_seconds, top_domains, stuck), плюс total_messages и общий для шлюза stuck. oldest_age_seconds — нижняя граница: qshape сообщает возрастные интервалы.
GET/api/targets/{id}/pmg/trafficИтоги за сегодня (mail), недавняя кривая трафика (recent), гистограмма спам-оценок, вирусы, пойманные сегодня, и счётчики карантина (quarantine). Только счётчики: без содержимого сообщений.
GET/api/targets/{id}/pmg/healthОдна запись на узел (система, службы, signatures с family, age_seconds и stale, expiring_certificates, обновления, подписка), члены cluster с их состоянием синхронизации и stopped_services по всем узлам.
МетодМаршрутНазначение
GET/api/targets/{id}/synologyОбзор монитора synology по последнему опросу: system (модель, версия DSM, аптайм, температура, CPU, память), volumes (name, fs_type, raid_type, status, severity, total_bytes, used_bytes), disks (model, serial, kind, ssd, status, smart_status, temperature_celsius, size_bytes, remaining_life_percent, …) и sampled_at. 404, когда монитора не существует, 400, когда это не Synology.
GET/api/targets/{id}/synology/abbActive Backup for Business: tasks и devices — по одному отчёту на защищаемое устройство с выученной периодичностью в assessment (state, last_success_s, typical_interval_s, счётчики за 30 дней).
МетодМаршрутAuthНазначение
GET или POST/api/push/{token}none (токен)Вызов, который задание делает при каждом запуске. Необязательно ?status=up|down&msg=… (совместимо с Uptime Kuma). 204 пустой при успехе, 404 для неизвестного токена, 400 для другого status, 429 с Retry-After сверх шестидесяти вызовов в минуту на токен. См. Heartbeat.
GET/api/targets/{id}/pushsessionМонитор push: token, path (/api/push/<token>), last_seen_at, last_seen_age_secs, last_status, last_message, received_total, expected_interval_secs, grace_secs, settings_error, verdict (waiting, on_time, missed, reported_down). Создаётся при первом чтении. 400, когда монитор не является heartbeat.
POST/api/targets/{id}/push/regenerateadminНовый токен; прежний URL с этого момента отвечает 404. Тело то же, что при чтении.

Встроенный сервер Model Context Protocol, тот, с которым общается ассистент. Он аутентифицируется описанными выше API-токенами — те же области, срок действия, сети и ограничение частоты — и никогда не использует сессию.

МетодМаршрутAuthНазначение
POST/api/mcpAPI-токенJSON-RPC 2.0 поверх транспорта Streamable HTTP, один запрос на POST, ответ в JSON. Протокол 2026-07-28 (без состояния: каждый запрос несёт свою версию и возможности клиента в _meta, плюс заголовки MCP-Protocol-Version, Mcp-Method и Mcp-Name; server/discover), а также 2025-11-25, 2025-06-18 и 2025-03-26 через рукопожатие initialize. Без сессии: Mcp-Session-Id не выдаётся, присланный игнорируется. Уведомление получает 202 и пустое тело.
GET, DELETE/api/mcppublic405 с Allow: POST — потока, отправляемого сервером, и сессии для завершения нет; тело лишь сообщает, чем является этот эндпоинт.

tools — единственная возможность: ни ресурсов, ни промптов, ни OAuth. Из 27 инструментов токен read может вызывать 15, которые только читают (get_status, list_devices, get_device, list_alerts, alert_history, query_metrics, list_silences, list_rules, list_device_types, list_agents, list_containers, list_heartbeats, list_status_pages, list_channels, list_packs); 12, которые что-то изменяют (silence_device, remove_silence, acknowledge_alert, probe_device, set_device_enabled, set_rule_enabled, add_device, discover_network, schedule_maintenance, restart_container, test_channel, post_incident), требуют токен write. Инструменты вызывают тот же код, что и веб-интерфейс. Версии, заголовки, коды ошибок и замечания по безопасности приведены в Подключение ассистента.

МетодМаршрутНазначение
GET/install.shУстановщик для Linux, macOS и FreeBSD. Публичный.
GET/install.ps1Установщик для Windows. Публичный.
GET/download/{name}dumbmonit-agent-linux-x86_64, dumbmonit-agent-linux-aarch64, dumbmonit-agent-freebsd-x86_64, dumbmonit-agent-windows-x86_64.exe, раздаются из DUMBMONIT_AGENT_DIR; {name}.sha256 даёт его контрольную сумму в формате sha256sum. 404, если файл отсутствует. dumbmonit-agent-macos-aarch64 и dumbmonit-agent-macos-x86_64 (и их .sha256) отвечают 307 на тот же файл в последнем релизе GitHub. Публичный.

Любой другой путь обслуживается веб-интерфейсом, который сам предложит вам войти.