API Reference
HTTP endpoints and WebSocket protocol
Authentication
All API endpoints except the health check, token-scoped shared views, and secret-authenticated webhook ingress require administrator authentication. Browsers use the session cookie obtained by logging in:
POST /api/auth/login
Content-Type: application/json
{ "password": "your-password" }Development automation
When the Server is started from the repository with bun run dev:server, the
launcher binds the API to loopback and creates an ephemeral 256-bit development
credential. Agents and local scripts should use the request wrapper; they do not
need to handle or print the credential:
bun run dev:server:request -- GET /api/topologies
bun run dev:server:request -- POST /api/topologies/example/rebuild
bun run dev:server:request -- PATCH /api/topologies/example/discovery-policy \
--json '{"scope":"topology","attachments":[]}'The wrapper uses the standard Authorization: Bearer scheme. This path is
available only when NODE_ENV=development, requires the API to be bound to
127.0.0.1 or ::1, accepts only normalized /api/* paths, and refuses to
send the generated credential to any remote HTTP or HTTPS origin. Production
continues to accept session authentication only. The credential is stored in a
gitignored owner-only file while the API is running and is removed on shutdown.
Starting apps/server/api directly with bun run dev does not create this
credential; use the server-level command above when automating API access.
Machine-readable contract
GET /api/openapi.json returns the OpenAPI 3.1 contract. It requires the same
administrator session or development Bearer credential as management endpoints:
bun run dev:server:request -- GET /api/openapi.jsonRequest and response schemas are the source of truth for every HTTP route, and request schemas also perform runtime validation. The document covers management, sharing, discovery, rendering, mapping, sync, plugins, and webhook ingress.
For repository development, bun run openapi:generate writes the deterministic
apps/server/api/openapi.json snapshot and the web client's generated TypeScript
definitions. The web client consumes those definitions with openapi-fetch;
raw fetch is reserved for multipart upload and the tagged-Map view payload.
Every operation has a deterministic, unique operationId derived from its HTTP
method and path, so generated SDK names remain stable while the route remains
stable. CI checks artifact drift, requires every runtime HTTP route to exist in
OpenAPI, and runs oasdiff against the PR base branch. Definite and potential
breaking changes fail the compatibility check and must be redesigned or handled
as an intentional versioned change.
Error responses
JSON error responses use one envelope across validation, authentication, and feature routes:
{
"code": "NOT_FOUND",
"message": "Topology not found",
"requestId": "00000000-0000-4000-8000-000000000000",
"error": "Topology not found"
}Clients should branch on code, display message, and include requestId when
reporting a failure. error is a deprecated alias of message retained for
compatibility with older clients.
Shared views (public, token-scoped)
The only endpoints reachable without a session are the share routes below
(plus /api/health). A share token grants read-only access to a single
topology — or, for a dashboard, to just the topology/data-source ids that
dashboard's widgets reference. Responses are projected to a public shape:
internal fields (the resource's own share token, data-source ids, host
mappings, port aliases, timestamps) are never returned.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/share/topologies/:token | Shared topology context (nodes/edges/metrics) |
| GET | /api/share/topologies/:token/graph | Shared topology as a NetworkGraph |
| GET | /api/share/topologies/:token/render | Shared topology render output |
| GET | /api/share/dashboards/:token | Shared dashboard shell (layout) |
| GET | /api/share/dashboards/:token/topologies/:id | Topology metadata for a widget in this dashboard |
| GET | /api/share/dashboards/:token/topologies/:id/graph | NetworkGraph for a widget in this dashboard |
| GET | /api/share/dashboards/:token/topologies/:id/context | Context for a device-status widget |
| GET | /api/share/dashboards/:token/datasources/:id/alerts | Alerts for an alert widget |
A dashboard-scoped request whose :id is not referenced by the dashboard's
layout returns 404, so the token cannot enumerate unrelated resources. The
management endpoints below (/api/topologies/:id, /api/dashboards/:id,
/api/datasources/:id/alerts, …) always require authentication.
HTTP Endpoints
Data Sources
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/datasources | List all data sources |
| POST | /api/datasources | Create data source |
| GET | /api/datasources/:id | Get data source details |
| PUT | /api/datasources/:id | Update data source |
| DELETE | /api/datasources/:id | Delete data source |
| GET | /api/datasources/types | List plugin types and form schemas |
| GET | /api/datasources/by-capability/:capability | List sources by capability |
| GET | /api/datasources/:id/config-options/:key | Get dynamic form options |
| GET | /api/datasources/:id/connection-info | Get display-only connection information |
| GET | /api/datasources/:id/topologies | List attached topologies |
| POST | /api/datasources/:id/test | Test connection |
| GET | /api/datasources/:id/hosts | List monitored hosts |
| GET | /api/datasources/:id/hosts/:hostId/items | Host metrics items |
| GET | /api/datasources/:id/alerts | Get alerts |
Topologies
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/topologies | List all topologies |
| POST | /api/topologies | Create topology |
| GET | /api/topologies/:id | Get topology details |
| PUT | /api/topologies/:id | Update topology |
| DELETE | /api/topologies/:id | Delete topology |
| GET | /api/topologies/:id/render | Get rendered layout data |
| GET | /api/topologies/:id/sources | List linked data sources |
| POST | /api/topologies/:id/sources | Link a data source |
Dashboards
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/dashboards | List all dashboards |
| POST | /api/dashboards | Create dashboard |
| GET | /api/dashboards/:id | Get dashboard details |
| PUT | /api/dashboards/:id | Update dashboard |
| DELETE | /api/dashboards/:id | Delete dashboard |
Plugins
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/plugins | List all plugins |
| POST | /api/plugins | Add plugin (URL/path/upload) |
| DELETE | /api/plugins/:id | Remove plugin |
Webhooks
Webhook endpoints do not use session authentication. Each request must instead
carry the webhook secret configured on the source, supplied via the
X-Webhook-Secret header (preferred) or a ?secret= query parameter. The
secret is compared in constant time; a missing secret returns 401, an unknown
target returns 404, and a wrong secret returns 401.
The general form is POST /api/webhooks/:type/:id, where :id is the id of
the source (shown in its settings, not the secret itself). type=topology
re-fetches a webhook-mode topology source's graph; any other type is dispatched
to the matching data-source plugin — currently only grafana handles webhooks.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/webhooks/topology/:id | Topology source webhook (:id = topology source id) — re-syncs the source, e.g. from NetBox |
| POST | /api/webhooks/grafana/:id | Grafana alert webhook (:id = data source id) |
| GET | /api/webhooks/health | Webhook health check |
Other
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health | Health check (no auth required) |
| GET | /api/system | Build and update information |
| GET | /api/admin/status | Redacted runtime, scheduler, plugin, and subscriber status |
| GET | /api/openapi.json | Authoritative OpenAPI 3.1 contract |
| GET | /api/auth/status | Check authentication state |
| POST | /api/auth/setup | Initial password setup |
| POST | /api/auth/logout | Logout |
WebSocket
Connect to ws://<host>/ws for real-time metrics streaming.
Client Messages
// Subscribe to topology updates
{ "type": "subscribe", "topology": "<topology-id>" }
// Filter specific nodes/links
{ "type": "filter", "nodes": ["router1"], "links": ["link-0"] }Server Messages
{
"type": "metrics",
"data": {
"nodes": {
"router1": { "status": "up" }
},
"links": {
"link-0": {
"status": "up",
"utilization": { "in": 45.2, "out": 12.8 }
}
},
"timestamp": 1705849200000
}
}