Home Network Monitor · Guide 11 of 12

API reference

REST API for building your own client or collector: authentication, endpoints and ingest formats.

Sections
6
Code samples
7
Time
~12 min
Visits
…

The backend is a standalone REST API. Anything the web UI does, a mobile app or script can do. Base path: /api/v1.

#Authentication

There are two kinds of caller:

Caller Credential Reaches
People and apps Authorization: Bearer <accessToken> Everything under /api/v1 except /ingest/**
Collector agents X-API-Key: <key> Only /api/v1/ingest/**

#Log in

$ curl -s -X POST http://192.168.1.2:8080/api/v1/auth/login \
    -H 'Content-Type: application/json' \
    -d '{"username":"admin","password":"your-password"}'

Response:

JSON
{
  "accessToken": "eyJ...",
  "refreshToken": "q2n...",
  "expiresInSeconds": 1800,
  "user": { "id": "…", "username": "admin", "role": "ROOT", "displayName": "…", "enabled": true }
}
$ curl -s http://192.168.1.2:8080/api/v1/devices -H "Authorization: Bearer eyJ..."

#Errors

Errors use RFC 7807 application/problem+json:

JSON
{ "status": 400, "title": "Bad Request", "detail": "Validation failed", "fields": { "password": "size must be between 10 and 128" } }

Common statuses: 400 invalid input, 401 missing/expired credential, 403 not allowed (for example an Admin calling a Root-only endpoint, or a blocked CORS origin), 404 not found, 409 conflict (for example a duplicate username), 429 account temporarily locked.

#Roles

Role Access
ROOT Everything, including creating, changing and deleting users
ADMIN Everything except user management (can list users)

#Endpoints

Dates are yyyy-MM-dd (server timezone); timestamps are ISO-8601 UTC. Paged lists return { items, page, size, totalItems, totalPages }.

#Setup and authentication

Method Path Notes
GET /setup/status Public. { "setupRequired": true } until the root user exists
POST /setup/root Public, works once. Body: username, displayName, email?, password (≥ 10 chars)
POST /auth/login Body: username, password
POST /auth/refresh Body: refreshToken
POST /auth/logout Body: refreshToken
GET /auth/me Current user
POST /auth/change-password Body: currentPassword, newPassword

#Users

Method Path Notes
GET /users Both roles
POST /users Root only. Creates an Admin
PATCH /users/{id} Root only. displayName, email, enabled. The root cannot be disabled
POST /users/{id}/reset-password Root only. Body: newPassword
DELETE /users/{id} Root only. The root cannot be removed

#Devices

Method Path Notes
GET /devices Query: status (ONLINE/OFFLINE), trusted (bool), q (name, IP, MAC)
GET /devices/{id}
PATCH /devices/{id} Body (any of): label, deviceType, trusted, parentId, clearParent
DELETE /devices/{id} Forgets the device and its history
GET /devices/{id}/usage Query: from, to (dates)
GET /devices/{id}/activity Query: date, domain, page, size

Device types: ROUTER, EXTENDER, ACCESS_POINT, PHONE, TABLET, LAPTOP, DESKTOP, TV, CONSOLE, IOT, PRINTER, UNKNOWN.

#Usage and web activity

Method Path Notes
GET /usage/daily Query: date (default today). Per-device bytesDown, bytesUp, bytesTotal, megabytes (1 MB = 1,048,576 bytes)
GET /usage/totals Query: from, to. Whole-network totals per day
GET /activity Query: deviceId, date, domain (contains), page, size (max 500)
GET /activity/top-domains Query: deviceId?, date?, limit (max 100)

#Alerts

Method Path Notes
GET /alerts Query: status (OPEN/ACKNOWLEDGED), severity (INFO/WARNING/CRITICAL), type, page, size
GET /alerts/open-count { "open": 3 } (good for a badge)
POST /alerts/{id}/acknowledge
POST /alerts/acknowledge-all

Alert types: NEW_DEVICE, DEVICE_IP_CONFLICT, EXTERNAL_CONNECTION_ATTEMPT, PORT_SCAN, LOGIN_BRUTE_FORCE, INTERNET_DOWN, INTERNET_RESTORED, COLLECTOR_FAILURE, BASELINE_ESTABLISHED.

#Overview and health

Method Path Notes
GET /dashboard Counts, today's totals, top devices and domains, internet state
GET /system/status Internet/gateway state and the health of each data source

#Settings

Secrets are masked (********) when read; send the mask back unchanged to keep the stored value.

Method Path Notes
GET / PUT /settings/network subnetCidr, gatewayIp, scanEnabled, scanIntervalSeconds (30–3600), offlineAfterSeconds (60–86400), activityRetentionDays (1–365)
POST /settings/network/scan Starts a scan now (202)
GET / PUT /settings/dns-collector type (NONE/PIHOLE/SIMULATED), url, password, pollSeconds
POST /settings/dns-collector/test Same body; returns { ok, message }
GET / PUT /settings/alerting telegramEnabled, telegramBotToken, telegramChatId, minNotifySeverity, disabledTypes, cooldownMinutes
POST /settings/alerting/test-telegram Same body; sends a test message
GET /settings/ingest { "keyConfigured": true }
POST /settings/ingest/rotate-key Returns the new key once

#Ingest (agents only)

Authenticate with the header X-API-Key: <key>. Batches are limited (5,000 items for usage and DNS, 1,000 for security events).

#POST /ingest/usage

Identify each device by mac (preferred) or ip. Send byte deltas since your last report.

JSON
{ "samples": [
  { "mac": "aa:bb:cc:dd:ee:ff", "bytesDown": 5242880, "bytesUp": 1048576, "timestamp": "2026-10-21T10:00:00Z" }
] }

Response: { "accepted": 1, "unmatched": 0 } (unmatched = devices not known yet; they are skipped).

#POST /ingest/dns

JSON
{ "events": [
  { "clientIp": "192.168.1.23", "domain": "example.com", "timestamp": "2026-10-21T10:00:03Z", "blocked": false }
] }

Use mac instead of clientIp if you have it.

#POST /ingest/security-events

JSON
{ "events": [
  { "type": "INBOUND_CONNECTION_ATTEMPT", "sourceIp": "198.51.100.7", "destPort": 22, "protocol": "TCP", "detail": "optional text" },
  { "type": "PORT_SCAN", "sourceIp": "198.51.100.7", "severity": "CRITICAL" }
] }

type is INBOUND_CONNECTION_ATTEMPT or PORT_SCAN; severity is optional. Repeats from the same source inside the cooldown window increment one alert's counter.

#Writing a client

Questions or feedback?

Stuck on a step, found a bug, or have an idea? Leave a note — 60 words max.

0 / 60 words