Watched domains

A watched domain is any domain, hosted here or at another provider, whose nameservers, DNSSEC chain, e-mail records, registration, certificates and availability we keep an eye on. No nameserver change is needed; proving ownership once is.

Scopes

These routes need monitor:read to read and monitor:write to change anything. They are not included when you create a key without an explicit scopes list: ask for them on purpose. A zone:* key gets 403 api_key_scope_missing here, and that separation is deliberate: registering a watched domain consumes plan quota and starts continuous probing of someone else's network on your behalf.

Ownership comes first

A public one-off diagnosis (/v1/diagnose) needs no login. Continuous watching is a different thing: it creates recurring load on third parties (RDAP, CT logs) in our name and, without a proven owner, would turn the platform into a way to watch other people's portfolios. So a new domain arrives verified: false and nothing is probed until the TXT record is published and confirmed.

A domain that is also an active zone here arrives verified: an active zone already required delegation plus proven ownership, and asking for a second proof would be paperwork with no gain.

The watched domain object

FieldTypeDescription
id integerUnique identifier of the watched domain.
name stringDomain, normalized to lowercase without trailing dot.
verified booleanWhether ownership has been proven. Nothing is probed until this is true.
verify_host string | nullWhat to type in the "Name" field of most DNS panels (they append the domain themselves).
verify_record string | nullThe full record name, for panels that expect it. Pasting this one into a panel that appends produces _quathos-verify.example.com.example.com: the most common mistake, and the quietest.
verify_value string | nullThe TXT value to publish. Disappears from the response once verified.
current_ns string[]Nameservers answering for the domain today; useful to tell the user which panel to publish the TXT in.
zone_id integer | nullLinked zone, when the same domain is also hosted here.
counts_against_quota booleanFalse for domains also served here: those are watched for free on every plan.
enabled booleanWhether the domain is being watched.
checks object[]One entry per check (only on the single-domain route). See below.

The check object

Returned inside checks on the single-domain route.

FieldTypeDescription
check_kind enumns_delegation · dnssec_ds · dnssec_sig_expiry · spf · dmarc · mx · registrar_expiry · tls_expiry · cert_issued · http_reachable
family enumdns · registry · tls · availability: which surface of the domain the check belongs to. Seven of the ten are not DNS.
status enumok · warn · fail · unknown. "unknown" means not measured: it never raises an alert and never clears one.
observed object | nullWhat was seen on the last measurement, shaped per check.
changed booleanWhat is observed now differs from the baseline the account accepted as normal.
last_checked_at datetime | nullLast measurement (UTC).
last_error string | nullWhy the last measurement could not be made.

unknown is not a failure

A TLD without RDAP, a CT log that is down, a TLS handshake that timed out: all of these come back as unknown with a reason. They never open an alert and never close one. A false alert here is worse than a missing one: it teaches the account to ignore the next.

Add domains to the portfolio

POST /orgs/{org_id}/watched-domains

Adds up to 100 domains in one call and returns them with the TXT record to publish.

Body parameters

ParameterTypeDescription
names requiredstring[]1 to 100 domains. The whole batch is all-or-nothing: if one name busts the quota, none are added.

Example

cURL
curl -X POST "https://api.monitor.quathos.com/v1/orgs/$ORG_ID/watched-domains" \
  -H "Authorization: Bearer $QUATHOS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "names": ["example.com"] }'
response · 201 Created
[
  {
    "id": 17,
    "name": "example.com",
    "verified": false,
    "verify_host": "_quathos-verify",
    "verify_record": "_quathos-verify.example.com",
    "verify_value": "qx-8Kd2v...",
    "current_ns": ["ns1.otherprovider.net", "ns2.otherprovider.net"],
    "zone_id": null,
    "counts_against_quota": true,
    "enabled": true,
    "checks": []
  }
]

Quota is checked per name, and the batch is atomic

A duplicate returns 409 watched_domain_exists; an invalid name, 422 watched_domain_invalid. Busting the plan quota returns 422 with X-Error-Code: monitor_quota_reached and nothing is added: a portfolio of fifty does not get halfway in because the tenth name hit the ceiling. Domains also served here as a zone never count against quota.

Verify ownership

POST /orgs/{org_id}/watched-domains/{domain_id}/verify

Reads the TXT record and flips the domain to verified. Watching starts on the next tick, not on the next scheduled cycle. Idempotent: once verified, it stays verified.

cURL
curl -X POST "https://api.monitor.quathos.com/v1/orgs/$ORG_ID/watched-domains/17/verify" \
  -H "Authorization: Bearer $QUATHOS_KEY"

Give DNS a moment

Returns 409 watched_domain_txt_missing while the record is not visible yet. We ask the domain's own nameservers with recursion disabled, so there is no resolver cache between us and the truth, but the record still has to exist at the provider. Poll every few seconds, not in a tight loop.

List & retrieve

GET /orgs/{org_id}/watched-domains

The portfolio, without the checks.

GET /orgs/{org_id}/watched-domains/{domain_id}

One domain with its checks, ordered by family (DNS, registry, TLS, availability) and then by the catalog order: the same order everywhere.

cURL
curl "https://api.monitor.quathos.com/v1/orgs/$ORG_ID/watched-domains/17" \
  -H "Authorization: Bearer $QUATHOS_KEY"
response · 200 OK
{
  "id": 17,
  "name": "example.com",
  "verified": true,
  "verify_host": null,
  "verify_record": null,
  "verify_value": null,
  "current_ns": ["ns1.otherprovider.net", "ns2.otherprovider.net"],
  "zone_id": null,
  "counts_against_quota": true,
  "enabled": true,
  "checks": [
    {
      "check_kind": "ns_delegation",
      "family": "dns",
      "status": "ok",
      "observed": { "nameservers": ["ns1.otherprovider.net", "ns2.otherprovider.net"] },
      "changed": false,
      "last_checked_at": "2026-09-12T18:20:04.551302",
      "last_error": null
    },
    {
      "check_kind": "http_reachable",
      "family": "availability",
      "status": "fail",
      "observed": { "url": "https://example.com/", "status_code": 502, "reason": "HTTP 502" },
      "changed": false,
      "last_checked_at": "2026-09-12T18:20:06.019874",
      "last_error": null
    }
  ]
}

Accept an expected change

POST /orgs/{org_id}/watched-domains/{domain_id}/acknowledge

Whoever changed nameservers on purpose does not want the same warning forever. This makes what is observed now the new baseline and closes the alert. Returns 409 monitor_check_invalid if the check has never been measured.

Body parameters

ParameterTypeDescription
check_kind requiredstringWhich check to accept. What is observed now becomes the new baseline and the alert closes.
cURL
curl -X POST "https://api.monitor.quathos.com/v1/orgs/$ORG_ID/watched-domains/17/acknowledge" \
  -H "Authorization: Bearer $QUATHOS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "check_kind": "ns_delegation" }'

Stop watching

DELETE /orgs/{org_id}/watched-domains/{domain_id}

Removes the domain from the portfolio, with its checks, hosts and open alerts. Returns 204 No Content and frees the quota slot.

cURL
curl -X DELETE "https://api.monitor.quathos.com/v1/orgs/$ORG_ID/watched-domains/17" \
  -H "Authorization: Bearer $QUATHOS_KEY"