Skip to content

Management API

import { Aside } from ‘@astrojs/starlight/components’;

The management API is served from /api/v1/* on the management listener (default: 127.0.0.1:8080). It is the shared control surface used by the web admin SPA, dnsctl, and operator automation.

The canonical REST contract is docs/openapi.yaml in the repo. TypeScript types for the web admin are generated from it via make api-types.


Requests are gated in this order:

  1. Network gatemanagement.allow_cidrs in YAML; requests outside these CIDRs are rejected before any auth check.
  2. Session cookiehomedns_session, issued by POST /auth/login.
  3. Bearer tokenAuthorization: Bearer <token> for tokens minted via POST /users/{id}/tokens.
CodeMeaning
401Missing or invalid credentials
403Authenticated but role is insufficient
404Resource does not exist (or hidden by feature flag)
409Conflict — e.g. zone already exists
400Validation failure
RoleAccess
adminFull control, including user management
operatorAll DNS and config operations
viewerRead-only

All paths below are relative to /api/v1.

PathMethodNotes
/healthGETReturns {"status":"ok"} when healthy
/versionGETReturns version, buildTime, debug

PathMethodNotes
/zonesGET, POSTList all zones; create a zone
/zones/{zone}GET, DELETEFetch or delete a zone
/zones/{zone}/recordsGET, POSTList or add records (JSON, zone-file presentation)
/zones/{zone}/recordsDELETEDelete a record
/zones/{zone}/importPOSTImport raw RFC 1035 zone file (text/plain body)
/zones/{zone}/exportGETDownload zone as text/plain zone file
/zones/{zone}/rrsetGETFetch a specific RRset (verify implementation)
/zones/{zone}/serial/incrementPOSTBump SOA serial (verify implementation)

PathMethodNotes
/forwardersGET, POSTList or create conditional forwarders
/forwarders/{id}GET, PUT, DELETEFetch, update, or delete a forwarder
/forwarders/health/streamGET (SSE)Live health and latency updates — see SSE channels

PathMethodNotes
/filter/sourcesGET, POSTList or add filter sources
/filter/sources/{id}GET, PUT, DELETEManage a specific source
/filter/sources/{id}/refreshPOSTForce-refresh a specific list
/filter/policyGET, PUTGet or update the global block policy
/filter/decideGETTest a domain — ?name=ads.example.com
/filter/refreshPOSTTrigger a bulk refresh of all sources

PathMethodNotes
/cache/statsGETCurrent cache statistics
/cache/flushPOSTFlush all cached records

PathMethodNotes
/ddns/tsigGET, POSTList or create TSIG keys
/ddns/tsig/{name}GET, DELETEFetch or delete a key
/ddns/policiesGETList all zone update policies
/ddns/policies/{zone}GET, PUTFetch or update policy for a zone

PathMethodNotes
/queriesGETRecent query log (paginated)
/queries/streamGET (SSE)Live query log — see SSE channels

PathMethodNotes
/statsGETSnapshot of cache/filter/health aggregates
/stats/streamGET (SSE)Rolling stats stream — see SSE channels

PathMethodNotes
/config/effectiveGETMerged runtime config
/config/fileGETOn-disk YAML config

PathMethodNotes
/server/listenersGETActive listener bindings and state
/server/reloadPOSTTrigger config reload
/server/probe/{forwarder_id}POSTFire a manual health probe for a forwarder

Additional paths (OpenAPI-defined — verify implementation)

Section titled “Additional paths (OpenAPI-defined — verify implementation)”

The following paths are defined in docs/openapi.yaml but may be in varying states of implementation. Check internal/api/ before building automation against them:

  • /auth/login, /auth/logout, /auth/me, /sessions/*
  • /users/*, /tokens/*
  • /dnssec/* (trust anchors, validator status)
  • /acl (DNS ACL config)
  • /backup, /restore
  • /metrics (Prometheus — roadmap item; use /stats in v1)

All three streams use the text/event-stream content type. The client helper in the web admin is web-admin/src/lib/api/sse.ts.

PathEvent namesPayload description
/api/v1/forwarders/health/streamsnapshot, healthFull snapshot on connect, then delta health updates per upstream
/api/v1/queries/streamqueryOne QueryLogEntry per resolved query
/api/v1/stats/streamstatsNested cache / filter / health aggregate map

  • Strategies and transports are serialized as strings ("parallel", "dot", etc.). The Go enum values are integers internally; the JSON marshaling is frozen in the contracts package.
  • TLS runtime objects (*tls.Config) are not serialized. API-level TLS knobs use explicit fields: skip_tls_verify, sni_override.
  • CA bundles and client certs are addressed by ID once the cert manager API lands (roadmap).
  • Records use zone-file presentation format in both request and response bodies.