Skip to content

Health, forwarding and users over the API

This page covers the operational endpoints with curl examples. All need a bearer token; see the API overview.

Terminal window
# List
curl -sk https://dtm.internal:8443/api/v1/healthchecks \
-H "Authorization: Bearer $DTM_TOKEN"
# Create a monitor-only check (status metrics, no DNS effect)
curl -sk -X POST https://dtm.internal:8443/api/v1/healthchecks \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{
"name": "web-check",
"protocol": "http",
"target": "10.0.1.10:80",
"interval_seconds": 15,
"timeout_seconds": 5,
"failure_threshold": 3,
"http_config": {"path": "/healthz", "expected_status": [200]}
}'

A check created directly on /api/v1/healthchecks is monitor-only: it probes and reports status (the dtm_health_check_status metric and the Health Checks page) but never gates any record’s DNS answers. To make answers health-aware, put a health_check_template on the record instead; see health checks.

For HTTP/HTTPS checks, http_config can also carry authentication (headers, oauth2, mtls, managed_identity) to probe secured backends; see authenticated health probes.

Script checks ("protocol": "script", admin-only and disabled by default) carry a script_config with the command and args to run. An optional script_config.timeout_seconds overrides the top-level probe timeout for the script run; like the top-level value, it must not exceed interval_seconds. From v1.0.5, script_config can instead name a managed script with script_id, and optionally script_version and script_hash; without a version, the check pins the latest one when you save it. A script_config with both a command and a script_id is refused. In the audit log, args values are masked (they routinely carry credentials) while the command itself is recorded verbatim.

Check current status:

Terminal window
# One check
curl -sk https://dtm.internal:8443/api/v1/healthchecks/<id>/status \
-H "Authorization: Bearer $DTM_TOKEN"
# All checks on this node
curl -sk https://dtm.internal:8443/api/v1/health/status \
-H "Authorization: Bearer $DTM_TOKEN"
Terminal window
# Default forwarder (where unmatched queries go)
curl -sk -X PUT https://dtm.internal:8443/api/v1/forwarders/default \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{"upstreams": ["168.63.129.16"], "enabled": true}'
# Conditional forwarder for one domain
curl -sk -X POST https://dtm.internal:8443/api/v1/forwarders \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{"domain": "corp.contoso.com.", "upstreams": ["10.0.0.1:53"], "comment": "AD DNS"}'
# Stub zone
curl -sk -X POST https://dtm.internal:8443/api/v1/stub-zones \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{"domain": "partner.local.", "hints": ["10.5.0.1:53"]}'

See forwarders and stub zones for the concepts.

Terminal window
curl -sk -X PUT https://dtm.internal:8443/api/v1/blocklist \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{"domains": ["doubleclick.net", "trackers.example"]}'

User management requires the admin role. See users and access.

Terminal window
# List users (password hashes are stripped)
curl -sk https://dtm.internal:8443/api/v1/users \
-H "Authorization: Bearer $DTM_TOKEN"
# Create a user (password >= 16 chars; role admin|editor|readonly)
curl -sk -X POST https://dtm.internal:8443/api/v1/users \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{"username": "alice", "password": "long-enough-password-1234", "role": "editor"}'
# Update a user's role / enabled / password
curl -sk -X PUT https://dtm.internal:8443/api/v1/users/<id> \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{"role": "readonly", "enabled": true}'
Terminal window
# List nodes with status, region, address
curl -sk https://dtm.internal:8443/api/v1/nodes \
-H "Authorization: Bearer $DTM_TOKEN"
# This node's own info
curl -sk https://dtm.internal:8443/api/v1/nodes/self \
-H "Authorization: Bearer $DTM_TOKEN"

Added in v1.0.7. Restart the DTM service on one node without touching its virtual machine, for example when a setting takes effect only after a restart. The Lifecycle page’s Restart service card does the same for the node the console is connected to. Send the request to the node you want to restart:

Terminal window
curl -sk -X POST https://<node>:8443/api/v1/lifecycle/restart \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1"

202 means the restart has started; the answer is sent before the node shuts down. The node stops reporting ready, waits out its drain grace so traffic moves to the other nodes, stops, starts again and rejoins the cluster, while the other nodes keep answering. Wait for it to report ready before you restart the next one.

It is refused with 409, naming the reason, when:

  • no other node in the cluster answers its readiness check, so the restart would leave nothing to answer DNS. A single-node deployment is always refused: restart its virtual machine in a maintenance window instead.
  • the node is already shutting down or restarting;
  • its service started less than a minute ago;
  • a node swap is in progress.

A 503 means the restart is not available on that node.

Only an admin can restart a node, and each restart is recorded in the audit log.

Terminal window
curl -sk "https://dtm.internal:8443/api/v1/audit?limit=100" \
-H "Authorization: Bearer $DTM_TOKEN"

Optional filters: user_id, user_name, resource, resource_id, action, plus from / to time bounds (RFC 3339 or YYYY-MM-DD). limit defaults to 50. Readable by editor and admin. GET /api/v1/audit/export streams the same data as NDJSON for archival; like the other export and backup GETs it requires the X-DTM-CSRF: 1 header, so include it in any scheduled job:

Terminal window
curl -sk https://<dtm>:8443/api/v1/audit/export \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1"

The stored audit log is bounded: entries beyond the configured retention are pruned oldest-first (see audit log retention). If you need audit evidence beyond that window, schedule the NDJSON export to immutable storage you control, for example a nightly job writing to an Azure Storage container with an immutability policy.

Each entry’s before and after are the changed object, base64-encoded inside the JSON. Probe secrets and other credentials are masked, as everywhere else in the audit log. The same encoding is used in the support bundle and in the AUDIT lines in the node’s system log.

Added in v1.0.7. Deleting a zone removes all its records. The zone’s delete entry carries a copy of them in a records array, with probe secrets masked:

  • The first 1,000 records, up to 4 MiB of them, are copied in full. Any after that are listed by id in omitted_record_ids.
  • record_count is the number of records the zone held, and records_sha256 is a SHA-256 fingerprint of all of them as DTM encoded them for the entry. Use it to check that two entries describe the same set; it cannot be recomputed from a zone export.

To keep every record of a larger zone in full, export the zone (GET /api/v1/zones/{id}/export, see the API reference) before you delete it.

Changed in v1.0.7. An AUDIT line in the node’s system log that would be longer than 32 KiB is written as numbered parts instead. Each part is an AUDIT line with "stream":"dtm-audit-part", the entry’s id, its part number, the number of parts and base64 data; the first part also carries the total bytes and a sha256 of the whole line. Decode each part’s data and join the parts in order to get back the ordinary "stream":"dtm-audit" line. Shorter entries are written as before.

Terminal window
curl -sk https://dtm.internal:8443/api/v1/stats \
-H "Authorization: Bearer $DTM_TOKEN"
# {"zones": 5, "records": 42, "nodes": 3, "users": 2}

For the complete endpoint list, see the endpoint reference.