The API endpoints, grouped by area. Base URL https://<dtm-node>:8443. All
endpoints need a bearer token unless marked public. See the
API overview for authentication and roles. Write operations
generally require editor; cluster and user operations require admin.
| Method |
Path |
Role |
Purpose |
| POST |
/api/v1/auth/login |
public |
Log in. Sets the JWT session cookie (valid 24h) and returns a refresh token. |
| POST |
/api/v1/auth/refresh |
public |
Exchange a refresh token for a bearer JWT. Rotates the refresh token. |
| POST |
/api/v1/auth/logout |
public |
Revoke a refresh token to end that session. Any user can end their own. |
| GET |
/api/v1/auth/entra/status |
public |
Whether Entra SSO is configured. |
| GET |
/api/v1/auth/entra/login |
public |
Start the Entra sign-in redirect. |
| GET |
/api/v1/auth/entra/callback |
public |
Entra sign-in callback (sets the session cookie). |
| GET |
/api/v1/auth/entra/config |
admin |
Read Entra config (secret redacted). |
| PUT |
/api/v1/auth/entra/config |
admin |
Update Entra config. |
| Method |
Path |
Role |
Purpose |
| GET |
/api/v1/zones |
read |
List zones. |
| POST |
/api/v1/zones |
editor |
Create a zone. Optional deletion_lock overrides the cluster default. |
| GET |
/api/v1/zones/{id} |
read |
Get a zone. |
| PUT |
/api/v1/zones/{id} |
editor |
Update a zone (TTL, SOA, default lb_policy; clear_lb_policy removes the default; deletion_lock toggles the deletion lock). |
| DELETE |
/api/v1/zones/{id} |
editor |
Delete a zone and its records; 409 while the deletion lock is set. |
| GET |
/api/v1/zones/{id}/export |
read |
Export one zone (RFC 1035). |
| POST |
/api/v1/zones/{id}/import |
editor |
Import records into a zone. |
| GET |
/api/v1/zones/export |
read |
Export all zones (JSON bundle). |
| POST |
/api/v1/zones/import |
editor |
Bulk import (JSON / CSV / BIND). |
| GET |
/api/v1/zones/{zoneId}/records |
read |
List records in a zone. |
| POST |
/api/v1/zones/{zoneId}/records |
editor |
Create a record. Replaces an unprotected record of the same name and type; a protected incumbent at that name and type answers 409. Other types at the same name coexist, except that CNAME and ALIAS own a name outright. auto_populate: true creates a registration-owned record with no values. |
| GET |
/api/v1/records/{id} |
read |
Get a record. |
| PUT |
/api/v1/records/{id} |
editor |
Update a record. Renaming onto a protected name answers 409. |
| DELETE |
/api/v1/records/{id} |
editor |
Delete a record (?force=true overrides protected). |
| POST |
/api/v1/zones/{zoneId}/records/bulk-delete |
editor |
Delete many records; capped (default 100), refuses over-cap batches whole. |
| POST |
/api/v1/zones/{id}/import-azure-privatedns |
admin |
Import an Azure Private DNS zone directly over ARM (managed identity, read-only; dry_run in the body). |
| POST |
/api/v1/overrides |
editor |
Create an override record. |
| GET/PUT/DELETE |
/api/v1/overrides/{id} |
mixed |
Manage an override record. |
| Method |
Path |
Purpose |
| POST |
/api/v1/service-accounts |
Create; returns the dtmsat_ token once. Optional zone_ids confines the token’s writes to the listed zones (fail-closed; preserved across rotation). |
| GET |
/api/v1/service-accounts |
List (tokens redacted). |
| GET |
/api/v1/service-accounts/{id} |
Get one (token redacted). |
| POST |
/api/v1/service-accounts/{id}/revoke |
Revoke; kept in the list for audit. |
| POST |
/api/v1/service-accounts/{id}/rotate |
Mint a fresh secret (version-gated, so repeated calls at the same version are a no-op). |
| DELETE |
/api/v1/service-accounts/{id} |
Delete. |
See service-account tokens.
| Method |
Path |
Role |
Purpose |
| GET |
/api/v1/healthchecks |
read |
List health checks. |
| POST |
/api/v1/healthchecks |
editor |
Create a monitor-only check: status metrics, no DNS effect (script protocol: admin, plus the config flag). |
| GET/PUT/DELETE |
/api/v1/healthchecks/{id} |
mixed |
Manage a check (admin to set the script protocol or edit script_config; other writes, including DELETE, are editor). |
| GET |
/api/v1/healthchecks/{id}/status |
read |
Status of one check. |
| GET |
/api/v1/health/status |
read |
Status of all checks on this node. |
| Method |
Path |
Role |
Purpose |
| GET/PUT |
/api/v1/forwarders/default |
mixed |
Default forwarder. |
| GET/PUT |
/api/v1/forwarders/hardening |
admin |
Default-forwarder hardening. |
| GET |
/api/v1/forwarders |
read |
List conditional forwarders. |
| POST |
/api/v1/forwarders |
editor |
Create a conditional forwarder. |
| GET/PUT/DELETE |
/api/v1/forwarders/{id} |
mixed |
Manage a forwarder. |
| GET |
/api/v1/stub-zones |
read |
List stub zones. |
| POST |
/api/v1/stub-zones |
editor |
Create a stub zone. |
| GET/PUT/DELETE |
/api/v1/stub-zones/{id} |
mixed |
Manage a stub zone. |
| GET |
/api/v1/blocklist |
read |
Get the blocklist. |
| PUT |
/api/v1/blocklist |
editor |
Replace the blocklist. |
| Method |
Path |
Role |
Purpose |
| GET |
/api/v1/users |
admin |
List users (hashes stripped). |
| POST |
/api/v1/users |
admin |
Create a user. |
| GET |
/api/v1/users/{id} |
admin |
Get a user. |
| PUT |
/api/v1/users/{id} |
admin |
Update role / enabled / password. |
| DELETE |
/api/v1/users/{id} |
admin |
Delete a user. |
| Method |
Path |
Role |
Purpose |
| GET |
/api/v1/nodes |
read |
List cluster members. |
| GET |
/api/v1/nodes/self |
read |
This node’s info. |
| DELETE |
/api/v1/nodes/{id} |
admin |
Remove a stopped node from the cluster (cannot remove self); see removing nodes. |
| POST |
/api/v1/cluster/join |
admin |
Join an existing cluster at runtime. |
The API behind the UI’s Lifecycle page; see
rolling upgrades for the procedure.
| Method |
Path |
Role |
Purpose |
| GET |
/api/v1/lifecycle/oracle |
read |
Latest published image version, as seen by the version oracle. |
| GET/POST |
/api/v1/lifecycle/swap |
mixed |
List stable-IP swap runs; start one (admin). |
| GET |
/api/v1/lifecycle/swap/{run_id} |
read |
One swap run’s state machine. |
| POST |
/api/v1/lifecycle/swap/{run_id}/retry |
admin |
Retry a failed swap step. |
| POST |
/api/v1/lifecycle/swap/{run_id}/abort |
admin |
Abort a swap run. |
| GET |
/api/v1/lifecycle/identity |
read |
Managed-identity permission probes for the swap. |
| Method |
Path |
Role |
Purpose |
| GET/POST/PUT/DELETE |
/api/v1/tsig-keys |
mixed |
Manage TSIG keys (update and delete by name). |
| GET/POST/DELETE |
/api/v1/subnet-mappings |
mixed |
Manage subnet-to-region mappings (delete by id: /api/v1/subnet-mappings/{id}). source must be manual on create; any other value is rejected. |
| GET |
/api/v1/regions |
read |
Deduplicated region IDs. |
| GET/POST/PUT/DELETE |
/api/v1/discovery/scopes |
admin |
Manage Azure discovery scopes: subscription scopes, or management-group scopes (kind: "management-group" + management_group_id + the required expanded_subscription_ids, since DTM never expands a group on its own). Reading the scope list also requires admin, matching the recon-sensitive siblings below. |
| GET |
/api/v1/discovery/available-subscriptions |
admin |
Subscriptions the identity can see. |
| GET |
/api/v1/discovery/available-management-groups |
admin |
Management groups the identity can see. ?management_group_id=<name> expands one, separating readable from unreadable member subscriptions; add &verify=true to test each with the same subscription-wide read discovery actually makes (one ARM call per subscription, opt-in). |
| POST |
/api/v1/discovery/run |
admin |
Discover and apply subnet mappings now; returns {upserted, removed, complete}. ?dry_run=true returns the diff an apply would make (additions, removals, new_regions) and writes nothing. Removals are only proposed or applied from a complete cycle. Also applies pending management-group membership drift (additions and true removals; a still-in-group subscription the identity lost access to is never dropped) before discovering. |
| GET |
/api/v1/discovery/status |
admin |
The periodic detector’s last result and pending drift, from memory (cheap to poll). {"observed": false} until a first cycle completes. Includes membership_drift per management-group scope: added / removed (proposals) and lost_access (reported, never proposed for removal). |
| POST |
/api/v1/tag-registration/run |
admin |
Run a tag-registration cycle now; returns {updated, drained, skipped, unclaimed}. |
| POST |
/api/v1/discovery/private-endpoints/run |
admin |
Run a Private Endpoint reconcile now; returns created/updated/reaped/unsupported counts. |
| Method |
Path |
Purpose |
| GET/PUT |
/api/v1/config/rate-limits |
Per-IP API rate limits in four classes (auth, write, read, upload; the upload class covers the disk-staging endpoints /api/v1/restore and /api/v1/admin/compact, with a deliberately severe default). GET reports the configured values, not what is in force: 0 means the built-in default applies, not that the limiter is off. |
| GET/PUT |
/api/v1/config/delete-guardrails |
Bulk-delete cap (bulk_delete_cap, default 100) and the default for new-zone deletion locks (default_zone_deletion_lock). |
| GET/PUT |
/api/v1/config/region-discovery |
Azure discovery backend (mode: arm-list or resource-graph). |
| GET/PUT |
/api/v1/config/axfr |
Zone-transfer (AXFR) settings, including outbound DNS NOTIFY (notify_targets, notify_tsig_key_name, notify_debounce_seconds); applies live, cluster-wide. See the configuration reference. |
| GET/PUT |
/api/v1/config/query-log |
Per-query logging (enabled, plus sample_rate to keep 1-in-N); applies live, cluster-wide. |
| GET/PUT |
/api/v1/config/dynamic-dns |
RFC 2136 dynamic-DNS settings. |
| GET/PUT |
/api/v1/config/cache |
Forwarded-response cache. |
| GET/PUT |
/api/v1/config/replication |
Cluster replication timing (applied on restart). |
| GET/PUT |
/api/v1/config/health-probe-policy |
TLS policy for authenticated probes (allow_insecure_authenticated_probes; audit-logged). |
| GET/PUT |
/api/v1/transport-config |
DNS-over-TLS and DNS-over-HTTPS listeners (dot_enabled, dot_listen_addr, doh_enabled, doh_listen_addr); applies live, cluster-wide. GET is readable by any authenticated role; PUT is admin. |
| GET/PUT |
/api/v1/observability/otlp |
OTLP metrics export. |
| Method |
Path |
Purpose |
| POST |
/api/v1/debug/enable |
Open a time-boxed debug logging window (admin). |
| POST |
/api/v1/debug/disable |
Close the window early (admin). |
| GET |
/api/v1/debug/status |
Whether the window is open (any authenticated role). |
| GET |
/api/v1/debug/tail |
The captured lines retained in memory on the node that answers (last 1000, with node_id, dropped and capacity); admin only. Debug capture is node-local, never replicated. |
| DELETE |
/api/v1/debug/tail |
Discard the answering node’s retained lines (admin). |
Both /api/v1/debug/tail calls require the X-DTM-CSRF: 1 header (the GET is
a sensitive read). The buffer is kept when the window closes or expires, so a
capture survives the window it was taken in. See
capture debug output.
| Method |
Path |
Purpose |
| GET |
/api/v1/backup |
Stream a point-in-time snapshot, optionally passphrase-encrypted (X-DTM-Backup-Passphrase header). |
| POST |
/api/v1/restore |
Stage a snapshot (applied on restart); an encrypted snapshot needs the same passphrase header. |
| POST |
/api/v1/admin/compact |
Stage a compacted database copy. |
| POST |
/api/v1/support-bundle |
Build a support bundle, optionally passphrase-encrypted. |
See backup and restore.
| Method |
Path |
Purpose |
| GET |
/healthz |
Liveness. |
| GET |
/readyz |
Readiness state. |
| GET |
/metrics |
Prometheus metrics. |
| GET/POST |
/dns-query |
DNS-over-HTTPS (RFC 8484), opt-in. Served by a dedicated listener on its own port (443 by default), never by the API port; the DoH listener serves nothing else. |
| Method |
Path |
Role |
Purpose |
| GET |
/api/v1/audit |
editor |
Query the audit log (filters: user_id, user_name, resource, resource_id, action, from, to, limit). |
| GET |
/api/v1/audit/export |
editor |
Export the audit log as NDJSON (same filters). |
| GET |
/api/v1/stats |
read |
Zone / record / node / user counts. |