Files
Dash/openapi.yaml
Tomas DvorakandDevin 041c54c18c feat(domains): per-record provider intel + vendor strip
Structured DNSRecord list carries the detected vendor per row (NS/MX/CNAME/
TXT value, ASN org, response headers, SPF includes, verification strings)
and a Providers strip shows registrar/DNS/hosting/email/CA with favicons —
the domainstack-style view. Detection tables expanded to ~70 NS, ~45 mail,
~60 CNAME, ~130 registrar, and ~50 TXT patterns.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-22 18:26:24 +02:00

2193 lines
57 KiB
YAML

openapi: 3.1.0
info:
title: Dash API
version: 0.1.0
description: >
Single source of truth for the Dash API. The TypeScript client in
packages/api-client is generated from this file — do not hand-write
API types in the frontend.
servers:
- url: /
paths:
/api/healthz:
get:
operationId: healthz
summary: Liveness + database reachability probe
responses:
"200":
description: Service healthy
content:
application/json:
schema:
$ref: "#/components/schemas/Health"
"503":
description: Database unreachable
content:
application/json:
schema:
$ref: "#/components/schemas/Health"
/api/boards:
get:
operationId: listBoards
summary: All boards, ordered
responses:
"200":
description: Board list
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Board"
post:
operationId: createBoard
summary: Create a board — slug derived from the name
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name:
type: string
responses:
"201":
description: Created board
content:
application/json:
schema:
$ref: "#/components/schemas/Board"
/api/boards/{id}:
patch:
operationId: updateBoard
summary: Rename a board — the slug stays stable
parameters:
- $ref: "#/components/parameters/id"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name:
type: string
responses:
"200":
description: Updated board
content:
application/json:
schema:
$ref: "#/components/schemas/Board"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteBoard
summary: Delete a board and its sections — the last board cannot be deleted
parameters:
- $ref: "#/components/parameters/id"
responses:
"204":
description: Deleted
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
/api/sections:
get:
operationId: listSections
summary: Board tree — sections with nested items and urls, ordered
parameters:
- name: board
in: query
description: Restrict to one board id; omitted returns all sections
schema:
type: string
responses:
"200":
description: Ordered board tree
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Section"
post:
operationId: createSection
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/SectionInput"
responses:
"201":
description: Created section
content:
application/json:
schema:
$ref: "#/components/schemas/Section"
/api/sections/{id}:
patch:
operationId: updateSection
parameters:
- $ref: "#/components/parameters/id"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/SectionPatch"
responses:
"200":
description: Updated section
content:
application/json:
schema:
$ref: "#/components/schemas/Section"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteSection
parameters:
- $ref: "#/components/parameters/id"
responses:
"204":
description: Section and its items deleted
/api/sections/reorder:
post:
operationId: reorderSection
summary: Move a section between two neighbors (fractional position)
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Reorder"
responses:
"200":
description: Reordered
content:
application/json:
schema:
$ref: "#/components/schemas/Section"
"404":
$ref: "#/components/responses/NotFound"
/api/items:
post:
operationId: createItem
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ItemInput"
responses:
"201":
description: Created item
content:
application/json:
schema:
$ref: "#/components/schemas/Item"
"400":
$ref: "#/components/responses/BadRequest"
/api/items/{id}:
patch:
operationId: updateItem
parameters:
- $ref: "#/components/parameters/id"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ItemPatch"
responses:
"200":
description: Updated item
content:
application/json:
schema:
$ref: "#/components/schemas/Item"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteItem
parameters:
- $ref: "#/components/parameters/id"
responses:
"204":
description: Item deleted
/api/items/{id}/icon:
post:
operationId: uploadIcon
summary: Upload an icon file; returns the stored icon reference
parameters:
- $ref: "#/components/parameters/id"
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [file]
properties:
file:
type: string
format: binary
responses:
"200":
description: Icon stored
content:
application/json:
schema:
$ref: "#/components/schemas/Item"
"400":
$ref: "#/components/responses/BadRequest"
/api/items/reorder:
post:
operationId: reorderItem
summary: Move an item between two neighbors, optionally across sections
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ItemReorder"
responses:
"200":
description: Reordered
content:
application/json:
schema:
$ref: "#/components/schemas/Item"
"404":
$ref: "#/components/responses/NotFound"
/api/icons/{file}:
get:
operationId: getIcon
summary: Serve an uploaded icon file
parameters:
- name: file
in: path
required: true
schema:
type: string
responses:
"200":
description: Icon bytes
"404":
$ref: "#/components/responses/NotFound"
/api/monitors:
get:
operationId: listMonitors
summary: All monitors with live uptime stats
responses:
"200":
description: Monitors ordered by position
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/MonitorView"
post:
operationId: createMonitor
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MonitorInput"
responses:
"201":
description: Created monitor
content:
application/json:
schema:
$ref: "#/components/schemas/MonitorView"
"400":
$ref: "#/components/responses/BadRequest"
/api/monitors/{id}:
get:
operationId: getMonitor
parameters:
- $ref: "#/components/parameters/id"
responses:
"200":
description: Monitor with stats
content:
application/json:
schema:
$ref: "#/components/schemas/MonitorView"
"404":
$ref: "#/components/responses/NotFound"
patch:
operationId: updateMonitor
summary: Sparse update; `active` toggles pause/resume
parameters:
- $ref: "#/components/parameters/id"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MonitorInput"
responses:
"200":
description: Updated monitor
content:
application/json:
schema:
$ref: "#/components/schemas/MonitorView"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteMonitor
parameters:
- $ref: "#/components/parameters/id"
responses:
"204":
description: Monitor and its heartbeats deleted
"404":
$ref: "#/components/responses/NotFound"
/api/monitors/{id}/heartbeats:
get:
operationId: monitorHeartbeats
parameters:
- $ref: "#/components/parameters/id"
- name: hours
in: query
schema:
type: integer
default: 24
maximum: 720
responses:
"200":
description: Check history, oldest first
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Heartbeat"
/api/monitors/{id}/check:
post:
operationId: checkMonitorNow
summary: Run one check synchronously
parameters:
- $ref: "#/components/parameters/id"
responses:
"200":
description: Monitor after the check
content:
application/json:
schema:
$ref: "#/components/schemas/MonitorView"
"404":
$ref: "#/components/responses/NotFound"
/api/push/{token}:
get:
operationId: pushMonitorGet
summary: Record an up heartbeat for a push monitor
parameters:
- name: token
in: path
required: true
schema:
type: string
- name: msg
in: query
schema:
type: string
- name: ping
in: query
schema:
type: integer
responses:
"200":
description: Heartbeat recorded
"404":
$ref: "#/components/responses/NotFound"
post:
operationId: pushMonitorPost
summary: Record an up heartbeat for a push monitor
parameters:
- name: token
in: path
required: true
schema:
type: string
- name: msg
in: query
schema:
type: string
- name: ping
in: query
schema:
type: integer
responses:
"200":
description: Heartbeat recorded
"404":
$ref: "#/components/responses/NotFound"
/api/domains:
get:
operationId: listDomains
summary: All tracked domains with expiry countdowns
responses:
"200":
description: Domains ordered by position
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/DomainView"
post:
operationId: createDomain
summary: Track a domain; runs the first WHOIS/DNS/SSL lookup inline
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DomainInput"
responses:
"201":
description: Domain after the initial lookup
content:
application/json:
schema:
$ref: "#/components/schemas/DomainView"
"400":
$ref: "#/components/responses/BadRequest"
"409":
description: Domain already tracked
/api/domains/{id}:
get:
operationId: getDomain
parameters:
- $ref: "#/components/parameters/id"
responses:
"200":
description: Domain detail
content:
application/json:
schema:
$ref: "#/components/schemas/DomainView"
"404":
$ref: "#/components/responses/NotFound"
patch:
operationId: updateDomain
summary: Sparse update — settings fields only; lookup data is refreshed separately
parameters:
- $ref: "#/components/parameters/id"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DomainInput"
responses:
"200":
description: Updated domain
content:
application/json:
schema:
$ref: "#/components/schemas/DomainView"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteDomain
parameters:
- $ref: "#/components/parameters/id"
responses:
"204":
description: Domain and its check history deleted
"404":
$ref: "#/components/responses/NotFound"
/api/domains/{id}/refresh:
post:
operationId: refreshDomain
summary: Re-run WHOIS/RDAP + DNS + TLS + geo lookup now
parameters:
- $ref: "#/components/parameters/id"
responses:
"200":
description: Domain after the refresh
content:
application/json:
schema:
$ref: "#/components/schemas/DomainView"
"404":
$ref: "#/components/responses/NotFound"
/api/domains/{id}/checks:
get:
operationId: domainChecks
summary: Snapshot history for change detection
parameters:
- $ref: "#/components/parameters/id"
- name: limit
in: query
schema:
type: integer
default: 50
maximum: 500
responses:
"200":
description: Snapshots, newest first
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/DomainCheck"
/api/widgets/types:
get:
operationId: widgetTypes
summary: Widget registry metadata — drives the add-widget dialog
responses:
"200":
description: Registered widget types
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/WidgetType"
/api/widgets/{id}/data:
get:
operationId: widgetData
summary: Live data for one widget item (~30s server-side cache)
parameters:
- $ref: "#/components/parameters/id"
responses:
"200":
description: Widget payload; shape depends on config.type
content:
application/json:
schema:
$ref: "#/components/schemas/WidgetData"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
"502":
description: Upstream service unreachable
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/api/status:
get:
operationId: getStatus
summary: Reachability of each service item's primary URL (~60s server cache)
responses:
"200":
description: Status map keyed by item id
content:
application/json:
schema:
type: object
additionalProperties:
$ref: "#/components/schemas/Status"
/api/domains/{id}/subdomains:
get:
operationId: listSubdomains
summary: Discovered subdomains for a domain
parameters:
- $ref: "#/components/parameters/id"
responses:
"200":
description: Subdomain rows, name-sorted
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Subdomain"
"404":
$ref: "#/components/responses/NotFound"
/api/domains/{id}/subdomains/refresh:
post:
operationId: refreshSubdomains
summary: Force a crt.sh + DNS discovery run, returns the updated list
parameters:
- $ref: "#/components/parameters/id"
responses:
"200":
description: Subdomain rows after the sweep
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Subdomain"
"404":
$ref: "#/components/responses/NotFound"
/api/notify/test:
post:
operationId: notifyTest
summary: Send a test notification through configured transports
description: >-
Fires a test event synchronously through every configured notify_*
transport, or only the transport named in the body. Returns a
transport -> "ok" | "error: ..." map.
requestBody:
content:
application/json:
schema:
type: object
properties:
transport:
type: string
enum: [webhook, slack, discord, telegram, gotify, ntfy, smtp]
responses:
"200":
description: Per-transport delivery results
content:
application/json:
schema:
type: object
properties:
results:
type: object
additionalProperties:
type: string
"400":
$ref: "#/components/responses/BadRequest"
/api/systems:
get:
operationId: listSystems
responses:
"200":
description: All monitored systems with their latest sample
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/System"
post:
operationId: createSystem
summary: Register a system; the returned token authenticates agent pushes
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name: { type: string }
responses:
"201":
description: Created system
content:
application/json:
schema:
$ref: "#/components/schemas/System"
"400":
$ref: "#/components/responses/BadRequest"
/api/systems/{id}:
parameters:
- $ref: "#/components/parameters/id"
get:
operationId: getSystem
responses:
"200":
description: System detail
content:
application/json:
schema:
$ref: "#/components/schemas/System"
"404":
$ref: "#/components/responses/NotFound"
patch:
operationId: patchSystem
summary: Rename or rotate the agent token
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
rotateToken: { type: boolean }
responses:
"200":
description: Updated system
content:
application/json:
schema:
$ref: "#/components/schemas/System"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteSystem
responses:
"204":
description: Deleted
"404":
$ref: "#/components/responses/NotFound"
/api/systems/{id}/stats:
parameters:
- $ref: "#/components/parameters/id"
get:
operationId: systemStats
summary: Stored agent samples for charting
parameters:
- name: hours
in: query
schema: { type: integer, default: 24, maximum: 168 }
responses:
"200":
description: Samples oldest-to-newest
content:
application/json:
schema:
type: array
items:
allOf:
- $ref: "#/components/schemas/StatSample"
- type: object
properties:
ts: { type: string, format: date-time }
"404":
$ref: "#/components/responses/NotFound"
/api/systems/ingest:
post:
operationId: ingestSystem
summary: "Agent push endpoint; Authorization: Bearer <system token>"
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/StatSample"
responses:
"200":
description: Sample stored
"401":
description: Missing or unknown token
"400":
$ref: "#/components/responses/BadRequest"
/api/incidents:
get:
operationId: listIncidents
parameters:
- name: status
in: query
description: "`open` filters to open+ack"
schema: { type: string }
responses:
"200":
description: Incidents newest-first, updates embedded
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Incident"
post:
operationId: createIncident
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/IncidentInput"
responses:
"201":
description: Created incident
content:
application/json:
schema:
$ref: "#/components/schemas/Incident"
"400":
$ref: "#/components/responses/BadRequest"
/api/incidents/{id}:
parameters:
- $ref: "#/components/parameters/id"
patch:
operationId: patchIncident
summary: Update fields; a status change appends a timeline entry
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/IncidentInput"
responses:
"200":
description: Updated incident
content:
application/json:
schema:
$ref: "#/components/schemas/Incident"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteIncident
responses:
"204":
description: Deleted
"404":
$ref: "#/components/responses/NotFound"
/api/incidents/{id}/updates:
parameters:
- $ref: "#/components/parameters/id"
post:
operationId: addIncidentUpdate
summary: Append a timeline note; `status` also moves the incident
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/IncidentInput"
responses:
"200":
description: Incident with updated timeline
content:
application/json:
schema:
$ref: "#/components/schemas/Incident"
"404":
$ref: "#/components/responses/NotFound"
/api/maintenance:
get:
operationId: listWindows
responses:
"200":
description: Maintenance windows newest-first
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/MaintenanceWindow"
post:
operationId: createWindow
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenanceWindowInput"
responses:
"201":
description: Created window
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenanceWindow"
"400":
$ref: "#/components/responses/BadRequest"
/api/maintenance/{id}:
parameters:
- $ref: "#/components/parameters/id"
delete:
operationId: deleteWindow
responses:
"204":
description: Deleted
"404":
$ref: "#/components/responses/NotFound"
/api/status-pages:
get:
operationId: listStatusPages
responses:
"200":
description: All status pages
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/StatusPage"
post:
operationId: createStatusPage
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/StatusPageInput"
responses:
"201":
description: Created page
content:
application/json:
schema:
$ref: "#/components/schemas/StatusPage"
"409":
description: Slug already in use
"400":
$ref: "#/components/responses/BadRequest"
/api/status-pages/{id}:
parameters:
- $ref: "#/components/parameters/id"
patch:
operationId: patchStatusPage
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/StatusPageInput"
responses:
"200":
description: Updated page
content:
application/json:
schema:
$ref: "#/components/schemas/StatusPage"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteStatusPage
responses:
"204":
description: Deleted
"404":
$ref: "#/components/responses/NotFound"
/api/status-pages/{slug}/public:
parameters:
- name: slug
in: path
required: true
schema: { type: string }
get:
operationId: publicStatus
summary: Live public view for a status page
responses:
"200":
description: Title, overall state, monitors, systems, incidents, maintenance
content:
application/json:
schema:
$ref: "#/components/schemas/PublicStatus"
"404":
$ref: "#/components/responses/NotFound"
/api/badge/{kind}/{file}:
parameters:
- name: kind
in: path
required: true
schema: { type: string, enum: [monitor, domain, system] }
- name: file
in: path
required: true
description: "Entity id, conventionally suffixed .svg"
schema: { type: string }
get:
operationId: badge
summary: Stateless SVG shield from live state
responses:
"200":
description: SVG badge
content:
image/svg+xml: {}
"404":
$ref: "#/components/responses/NotFound"
/api/metrics:
get:
operationId: metrics
summary: Prometheus text exposition
responses:
"200":
description: text/plain metrics
content:
text/plain: {}
/api/import/csv:
post:
operationId: importCSV
summary: "Bulk import from CSV; ?kind=monitors|domains"
parameters:
- name: kind
in: query
schema: { type: string, enum: [monitors, domains], default: monitors }
requestBody:
required: true
content:
text/csv:
schema: { type: string }
responses:
"200":
description: Import summary
content:
application/json:
schema:
type: object
properties:
created: { type: integer }
skipped: { type: integer }
errors:
type: array
items: { type: string }
"400":
$ref: "#/components/responses/BadRequest"
/api/settings:
get:
operationId: getSettings
responses:
"200":
description: All settings as key/value map
content:
application/json:
schema:
type: object
additionalProperties: true
put:
operationId: putSettings
summary: Merge settings (keys not sent are preserved)
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: true
responses:
"200":
description: Full settings map after merge
content:
application/json:
schema:
type: object
additionalProperties: true
/api/export:
get:
operationId: exportBoard
summary: Full JSON backup (sections, items, urls, settings)
responses:
"200":
description: Board export
content:
application/json:
schema:
$ref: "#/components/schemas/Export"
/api/import:
post:
operationId: importBoard
summary: Replace board state from an export payload
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Export"
responses:
"200":
description: Imported board tree
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Section"
"400":
$ref: "#/components/responses/BadRequest"
/api/import/external:
post:
operationId: importExternal
summary: >
Import a foreign dashboard config — Homepage services.yml, Homarr
JSON export, or Dashy conf.yml. Format is auto-detected; the board
is replaced and existing settings are preserved.
requestBody:
required: true
content:
application/octet-stream:
schema:
type: string
format: binary
application/json:
schema:
type: string
format: binary
text/yaml:
schema:
type: string
format: binary
responses:
"200":
description: Imported board tree
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Section"
"400":
$ref: "#/components/responses/BadRequest"
/api/auth/session:
get:
operationId: authSession
summary: Auth state — enabled flag, whether setup is needed, and current session
responses:
"200":
description: Session state
content:
application/json:
schema:
$ref: "#/components/schemas/AuthSession"
/api/auth/setup:
post:
operationId: authSetup
summary: Create the first local admin — only while no users exist
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [username, password]
properties:
username:
type: string
password:
type: string
minLength: 8
responses:
"201":
description: Admin created; session cookie set
"400":
$ref: "#/components/responses/BadRequest"
"409":
description: Setup already completed
/api/auth/login:
post:
operationId: authLogin
summary: Password login — sets a session cookie; rate-limited per IP
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [username, password]
properties:
username:
type: string
password:
type: string
responses:
"200":
description: Signed in
"401":
description: Invalid credentials
"429":
description: Too many attempts
/api/auth/logout:
post:
operationId: authLogout
summary: Destroy the current session
responses:
"204":
description: Signed out
/api/auth/disable:
post:
operationId: authDisable
summary: Turn authentication off — requires an active session
responses:
"204":
description: Disabled
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
parameters:
id:
name: id
in: path
required: true
schema:
type: string
responses:
NotFound:
description: Not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
BadRequest:
description: Invalid input
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
schemas:
Health:
type: object
required: [status]
properties:
status:
type: string
example: ok
AuthSession:
type: object
properties:
enabled:
type: boolean
setup:
type: boolean
description: True when auth is on but no user exists yet
authed:
type: boolean
username:
type: string
Error:
type: object
required: [error]
properties:
error:
type: string
Url:
type: object
required: [id, url, label]
properties:
id:
type: string
url:
type: string
format: uri
label:
type: string
description: Tag such as "local" / "external" or a custom label
position:
type: number
UrlInput:
type: object
required: [url]
properties:
url:
type: string
format: uri
label:
type: string
default: ""
Item:
type: object
required: [id, sectionId, kind, name, position, urls]
properties:
id:
type: string
sectionId:
type: string
kind:
type: string
enum: [service, widget]
name:
type: string
icon:
type: string
description: "/api/icons/<file> path or remote URL; empty = letter tile"
position:
type: number
config:
type: object
nullable: true
additionalProperties: true
description: Widget config (Phase 2); null for services
urls:
type: array
items:
$ref: "#/components/schemas/Url"
ItemInput:
type: object
required: [sectionId, name]
properties:
sectionId:
type: string
kind:
type: string
enum: [service, widget]
default: service
name:
type: string
icon:
type: string
config:
type: object
nullable: true
additionalProperties: true
description: Widget config — keys defined by the widget type's fields
urls:
type: array
items:
$ref: "#/components/schemas/UrlInput"
ItemPatch:
type: object
properties:
name:
type: string
icon:
type: string
config:
type: object
nullable: true
additionalProperties: true
urls:
type: array
description: Full replacement of the item's URL list
items:
$ref: "#/components/schemas/UrlInput"
Section:
type: object
required: [id, name, position, collapsed, boardId, items]
properties:
id:
type: string
name:
type: string
position:
type: number
collapsed:
type: boolean
boardId:
type: string
items:
type: array
items:
$ref: "#/components/schemas/Item"
Board:
type: object
required: [id, slug, name, position]
properties:
id:
type: string
slug:
type: string
name:
type: string
position:
type: number
SectionInput:
type: object
required: [name]
properties:
name:
type: string
boardId:
type: string
SectionPatch:
type: object
properties:
name:
type: string
collapsed:
type: boolean
Reorder:
type: object
required: [id]
properties:
id:
type: string
beforeId:
type: string
description: Neighbor now before the moved entity; null if first
afterId:
type: string
description: Neighbor now after the moved entity; null if last
ItemReorder:
allOf:
- $ref: "#/components/schemas/Reorder"
- type: object
properties:
sectionId:
type: string
description: Target section (defaults to current)
Status:
type: object
required: [status]
properties:
status:
type: string
enum: [up, down]
latencyMs:
type: integer
checkedAt:
type: string
format: date-time
Monitor:
type: object
required: [id, name, type, active, status]
properties:
id:
type: string
name:
type: string
type:
type: string
enum: [http, tcp, ping, dns, keyword, json, push]
url:
type: string
hostname:
type: string
port:
type: integer
method:
type: string
headers:
type: string
description: JSON object of request headers
body:
type: string
keyword:
type: string
keywordInvert:
type: boolean
jsonQuery:
type: string
description: Dot path into a JSON response, e.g. "data.status"
expected:
type: string
dnsType:
type: string
intervalS:
type: integer
timeoutS:
type: integer
retries:
type: integer
active:
type: boolean
status:
type: string
enum: [up, down, pending, paused, maintenance]
pushToken:
type: string
tags:
type: array
items:
type: string
notes:
type: string
alerts:
$ref: "#/components/schemas/AlertRules"
position:
type: number
lastCheck:
type: string
format: date-time
nullable: true
createdAt:
type: string
format: date-time
AlertRules:
type: object
description: Per-target alert rules; omitted fields keep defaults.
properties:
consecutiveFailures:
type: integer
description: Checks must fail N times in a row before status flips down
latencyWarnMs:
type: integer
description: Notify once when an up check's ping crosses this threshold
certDays:
type: integer
description: Domain TLS expiry threshold; overrides alertDaysBefore
mute:
type: boolean
description: Suppress notifications; incidents/status still record
MonitorInput:
type: object
properties:
name:
type: string
type:
type: string
enum: [http, tcp, ping, dns, keyword, json, push]
url:
type: string
hostname:
type: string
port:
type: integer
method:
type: string
headers:
type: string
body:
type: string
keyword:
type: string
keywordInvert:
type: boolean
jsonQuery:
type: string
expected:
type: string
dnsType:
type: string
intervalS:
type: integer
timeoutS:
type: integer
retries:
type: integer
active:
type: boolean
tags:
type: array
items:
type: string
notes:
type: string
alerts:
$ref: "#/components/schemas/AlertRules"
UptimeStats:
type: object
properties:
up:
type: integer
down:
type: integer
uptime24h:
type: number
uptime30d:
type: number
avgPing24h:
type: integer
MonitorView:
allOf:
- $ref: "#/components/schemas/Monitor"
- type: object
properties:
stats:
$ref: "#/components/schemas/UptimeStats"
Heartbeat:
type: object
properties:
id:
type: integer
status:
type: string
enum: [up, down]
pingMs:
type: integer
msg:
type: string
certExpiry:
type: integer
checkedAt:
type: string
format: date-time
Domain:
type: object
required: [id, name, active]
properties:
id:
type: string
name:
type: string
tld:
type: string
active:
type: boolean
autoRenew:
type: boolean
alertDaysBefore:
type: integer
tags:
type: array
items:
type: string
notes:
type: string
expiryDate:
type: string
format: date-time
nullable: true
creationDate:
type: string
format: date-time
nullable: true
updatedDate:
type: string
format: date-time
nullable: true
registrarName:
type: string
registrarId:
type: string
registrarUrl:
type: string
registryDomainId:
type: string
dnssec:
type: string
statuses:
type: array
items:
type: string
privacyEnabled:
type: boolean
transferLock:
type: boolean
registrantName:
type: string
registrantOrg:
type: string
registrantCountry:
type: string
abuseEmail:
type: string
nameServers:
type: array
items:
type: string
mxRecords:
type: array
items:
type: string
txtRecords:
type: array
items:
type: string
cname:
type: string
ipv4:
type: array
items:
type: string
ipv6:
type: array
items:
type: string
sslIssuer:
type: string
sslValidFrom:
type: string
format: date-time
nullable: true
sslValidTo:
type: string
format: date-time
nullable: true
sslSubject:
type: string
sslFingerprint:
type: string
sslKeySize:
type: integer
sslSigAlgo:
type: string
sslAltNames:
type: array
items:
type: string
hostCountry:
type: string
hostCountryCode:
type: string
hostRegion:
type: string
hostCity:
type: string
hostIsp:
type: string
hostOrg:
type: string
hostAs:
type: string
hostLat:
type: number
hostLon:
type: number
dnsProvider:
type: string
emailProvider:
type: string
hostingProvider:
type: string
caProvider:
type: string
records:
type: array
items:
$ref: "#/components/schemas/DNSRecord"
providers:
$ref: "#/components/schemas/Providers"
headers:
type: object
additionalProperties:
type: string
faviconUrl:
type: string
lookupError:
type: string
intervalH:
type: integer
lastChecked:
type: string
format: date-time
nullable: true
alerts:
$ref: "#/components/schemas/AlertRules"
position:
type: number
createdAt:
type: string
format: date-time
DomainInput:
type: object
properties:
name:
type: string
active:
type: boolean
autoRenew:
type: boolean
alertDaysBefore:
type: integer
intervalH:
type: integer
tags:
type: array
items:
type: string
notes:
type: string
alerts:
$ref: "#/components/schemas/AlertRules"
Provider:
type: object
description: Detected vendor behind a record or role
properties:
name:
type: string
domain:
type: string
description: brand domain the favicon icon was derived from
icon:
type: string
Providers:
type: object
description: Detected vendor strip — registrar, DNS, hosting, email, CA
properties:
registrar:
$ref: "#/components/schemas/Provider"
nullable: true
dns:
$ref: "#/components/schemas/Provider"
nullable: true
email:
$ref: "#/components/schemas/Provider"
nullable: true
hosting:
$ref: "#/components/schemas/Provider"
nullable: true
ca:
$ref: "#/components/schemas/Provider"
nullable: true
DNSRecord:
type: object
properties:
type:
type: string
enum: [A, AAAA, CNAME, NS, MX, TXT]
value:
type: string
priority:
type: integer
nullable: true
description: MX preference
provider:
$ref: "#/components/schemas/Provider"
nullable: true
DomainView:
allOf:
- $ref: "#/components/schemas/Domain"
- type: object
properties:
daysUntilExpiry:
type: integer
nullable: true
sslDaysUntilExpiry:
type: integer
nullable: true
expiring:
type: boolean
sslExpiring:
type: boolean
Subdomain:
type: object
properties:
name:
type: string
ips:
type: array
items:
type: string
firstSeen:
type: string
format: date-time
lastSeen:
type: string
format: date-time
DomainCheck:
type: object
properties:
id:
type: integer
expiryDate:
type: string
format: date-time
nullable: true
sslValidTo:
type: string
format: date-time
nullable: true
ipv4:
type: array
items:
type: string
nameServers:
type: array
items:
type: string
checkedAt:
type: string
format: date-time
StatSample:
type: object
description: One agent push; missing fields mean the platform can't provide them
properties:
host: { type: string }
os: { type: string }
arch: { type: string }
cpuModel: { type: string }
cores: { type: integer }
intervalS: { type: integer }
uptimeS: { type: number }
cpu:
type: number
description: CPU usage percent 0-100
memTotal: { type: number, description: bytes }
memUsed: { type: number, description: bytes }
swapTotal: { type: number, description: bytes }
swapUsed: { type: number, description: bytes }
diskTotal: { type: number, description: root filesystem bytes }
diskUsed: { type: number, description: bytes }
netRx: { type: number, description: bytes per second }
netTx: { type: number, description: bytes per second }
load1: { type: number }
load5: { type: number }
load15: { type: number }
temps:
type: object
additionalProperties: { type: number }
description: Sensor label -> celsius
containers:
type: array
items:
$ref: "#/components/schemas/ContainerStat"
smart:
type: array
items:
$ref: "#/components/schemas/SmartDisk"
zfs:
type: array
items:
$ref: "#/components/schemas/ZFSPool"
gpu:
type: array
items:
$ref: "#/components/schemas/GPUStat"
ContainerStat:
type: object
properties:
name: { type: string }
state: { type: string }
cpu: { type: number, description: "percent of one core, may exceed 100" }
memUsed: { type: number, description: bytes }
memLimit: { type: number, description: bytes }
SmartDisk:
type: object
properties:
device: { type: string }
model: { type: string }
passed: { type: boolean, nullable: true }
tempC: { type: number }
ZFSPool:
type: object
properties:
name: { type: string }
health: { type: string }
size: { type: number, description: bytes }
free: { type: number, description: bytes }
GPUStat:
type: object
properties:
name: { type: string }
tempC: { type: number }
utilPct: { type: number }
memUsed: { type: number, description: bytes }
memTotal: { type: number, description: bytes }
System:
type: object
required: [id, name, token, status]
properties:
id: { type: string }
name: { type: string }
token:
type: string
description: Agent bearer token
host: { type: string }
os: { type: string }
arch: { type: string }
cpuModel: { type: string }
cores: { type: integer }
intervalS: { type: integer }
status:
type: string
enum: [pending, up, down]
lastSeenAt:
type: string
format: date-time
nullable: true
latest:
$ref: "#/components/schemas/StatSample"
createdAt:
type: string
format: date-time
IncidentUpdate:
type: object
properties:
id: { type: integer }
status: { type: string }
message: { type: string }
at: { type: string, format: date-time }
Incident:
type: object
required: [id, title, severity, status]
properties:
id: { type: string }
title: { type: string }
severity: { type: string, enum: [minor, major, critical] }
status: { type: string, enum: [open, ack, resolved, closed] }
monitorId: { type: string, nullable: true }
updates:
type: array
items:
$ref: "#/components/schemas/IncidentUpdate"
createdAt: { type: string, format: date-time }
updatedAt: { type: string, format: date-time }
IncidentInput:
type: object
properties:
title: { type: string }
severity: { type: string, enum: [minor, major, critical] }
status: { type: string, enum: [open, ack, resolved, closed] }
monitorId: { type: string }
message:
type: string
description: Timeline note attached to the create/transition
MaintenanceWindow:
type: object
required: [id, title, startsAt, endsAt]
properties:
id: { type: string }
title: { type: string }
startsAt: { type: string, format: date-time }
endsAt: { type: string, format: date-time }
monitorIds:
type: array
items: { type: string }
description: Empty array covers all monitors
active: { type: boolean }
createdAt: { type: string, format: date-time }
MaintenanceWindowInput:
type: object
required: [title, startsAt, endsAt]
properties:
title: { type: string }
startsAt: { type: string, format: date-time }
endsAt: { type: string, format: date-time }
monitorIds:
type: array
items: { type: string }
StatusPage:
type: object
required: [id, slug, title]
properties:
id: { type: string }
slug: { type: string }
title: { type: string }
description: { type: string }
monitorIds:
type: array
items: { type: string }
description: Empty array means all active monitors
systemIds:
type: array
items: { type: string }
createdAt: { type: string, format: date-time }
StatusPageInput:
type: object
required: [title]
properties:
slug: { type: string }
title: { type: string }
description: { type: string }
monitorIds:
type: array
items: { type: string }
systemIds:
type: array
items: { type: string }
PublicStatus:
type: object
properties:
title: { type: string }
slug: { type: string }
description: { type: string }
overall: { type: string, enum: [up, down, maintenance, pending] }
monitors:
type: array
items:
type: object
properties:
id: { type: string }
name: { type: string }
status: { type: string }
uptime24h: { type: number }
systems:
type: array
items:
type: object
properties:
id: { type: string }
name: { type: string }
status: { type: string }
incidents:
type: array
items:
$ref: "#/components/schemas/Incident"
maintenance:
type: array
items:
$ref: "#/components/schemas/MaintenanceWindow"
WidgetField:
type: object
required: [key, label]
properties:
key:
type: string
label:
type: string
secret:
type: boolean
description: Render as password input; never logged
placeholder:
type: string
required:
type: boolean
WidgetType:
type: object
required: [type, name, fields]
properties:
type:
type: string
name:
type: string
description:
type: string
local:
type: boolean
description: Client-rendered (e.g. clock); no /data fetch needed
fields:
type: array
items:
$ref: "#/components/schemas/WidgetField"
WidgetData:
type: object
required: [data]
properties:
data:
type: object
additionalProperties: true
fetchedAt:
type: string
format: date-time
Export:
type: object
required: [version, sections]
properties:
version:
type: integer
settings:
type: object
additionalProperties: true
sections:
type: array
items:
$ref: "#/components/schemas/Section"
boards:
type: array
items:
$ref: "#/components/schemas/Board"