Hosts & services
A watched domain is more than its apex. Every host below it (api., webmail., mx1.) serves a certificate of its own and answers, or stops answering, on its own. Hosts live under the domain, and every route here requires the domain to be verified first.
Scopes
Two quotas, both per domain
limit: certificate hosts in the inventory.services_limit: service checks across all hosts of the domain. A paused profile costs nothing and takes no slot.
Both come back on every response of these routes, next to the current usage.
The host object
| Field | Type | Description |
|---|---|---|
id | integer | Unique identifier of the host. |
hostname | string | A name strictly below the watched domain. The apex is covered by the tls_expiry check, not here. |
source | enum | zone · ct · manual: where the host came from. |
enabled | boolean | Whether the host is being checked. |
status | enum | ok · warn · fail · unknown, for the certificate. |
not_after | datetime | null | Certificate expiry (UTC). |
days_left | integer | null | Days until expiry; negative once expired. |
issuer | string | null | Issuer, RFC 4514 string. |
sans | string[] | Subject alternative names on the served certificate. |
chain_valid | boolean | null | Whether the chain validated. |
changed | boolean | The certificate served now is not the one accepted as normal. |
services | object[] | Service profiles switched on for this host. See below. |
The service check object
| Field | Type | Description |
|---|---|---|
profile | enum | web · webmail · email: a value from the catalog. |
status | enum | ok · warn · fail · unknown. The worst of the profile's probes, with unknown above ok and below fail. |
latency_ms | integer | null | Slowest healthy probe of the last cycle. |
probes | object[] | null | One entry per probe: target, protocol, ok, latency_ms, reason, detail, unknown. |
first_ok_at | datetime | null | When the service was first seen up. While null, a failure is state on the panel and never an alert. |
last_checked_at | datetime | null | Last measurement (UTC). |
last_error | string | null | Why the last measurement failed, per protocol. |
The profile catalog
| Profile | Type | Description |
|---|---|---|
web | HTTPS 443 | Website or API. Anything below 500 counts as up; TLS validation is off here on purpose, because the certificate is the inventory's job. |
webmail | HTTPS 443 + IMAP 993 | The login page and the IMAP behind it. A * OK or * PREAUTH banner is healthy. |
email | SMTP 25 | Incoming mail, read by the 220 banner, not just an open port. |
There is no port field, and that is the design
422 service_profile_unknown.We never sign in
Discover hosts
/orgs/{org_id}/watched-domains/{domain_id}/hosts/discoverFills the inventory from your zone here (when the domain is also hosted with us) and from public CT logs, up to the quota, and switches on the service profile each new host most likely needs: being an MX of the domain wins, then the leftmost label, otherwise web. Hosts that already carry a profile, switched on or paused, are never touched, because that was somebody's decision.
curl -X POST "https://api.monitor.quathos.com/v1/orgs/$ORG_ID/watched-domains/17/hosts/discover" \
-H "Authorization: Bearer $QUATHOS_KEY"{
"hosts": [ … ],
"used": 4,
"limit": 25,
"services_used": 4,
"services_limit": 15,
"added": 4,
"skipped_quota": 0,
"skipped_unresolved": 2,
"services_added": 4,
"services_skipped_quota": 0
}skipped_unresolved counts names that do not resolve to a public IP; those are not added and do not consume quota.
Add a host by hand
/orgs/{org_id}/watched-domains/{domain_id}/hostsBody parameters
| Parameter | Type | Description |
|---|---|---|
hostname required | string | A name strictly below the watched domain. Wildcards and the apex are rejected; the name must resolve to a public IP. |
curl -X POST "https://api.monitor.quathos.com/v1/orgs/$ORG_ID/watched-domains/17/hosts" \
-H "Authorization: Bearer $QUATHOS_KEY" \
-H "Content-Type: application/json" \
-d '{ "hostname": "api.example.com" }'409 certificate_host_exists if the host is already there, 409 certificate_domain_unverified if the domain has not proven ownership, and 422 for an invalid name, a name outside the domain or one that does not resolve publicly.
List the inventory
/orgs/{org_id}/watched-domains/{domain_id}/hostsEvery host with its certificate, its service profiles and both quotas. Paused profiles are not listed: what comes back is what is being watched.
Switch a service on
/orgs/{org_id}/watched-domains/{domain_id}/hosts/{host_id}/servicesStarts watching one profile on this host. The first probe runs on the next tick, not on the next plan cycle. Switching on a profile that is already on returns 409 service_check_exists; a previously paused one is simply resumed.
Body parameters
| Parameter | Type | Description |
|---|---|---|
profile required | string | web · webmail · email. Anything else returns 422: the catalog is closed. |
Example
curl -X POST "https://api.monitor.quathos.com/v1/orgs/$ORG_ID/watched-domains/17/hosts/88/services" \
-H "Authorization: Bearer $QUATHOS_KEY" \
-H "Content-Type: application/json" \
-d '{ "profile": "webmail" }'{
"hosts": [
{
"id": 88,
"hostname": "webmail.example.com",
"source": "ct",
"enabled": true,
"status": "ok",
"days_left": 63,
"issuer": "CN=R11,O=Let's Encrypt,C=US",
"changed": false,
"services": [
{
"profile": "webmail",
"enabled": true,
"status": "fail",
"latency_ms": 118,
"probes": [
{ "target": "https://webmail.example.com/", "protocol": "https", "ok": true,
"latency_ms": 118, "reason": null, "detail": "200", "unknown": false },
{ "target": "webmail.example.com:993", "protocol": "imap", "ok": false,
"latency_ms": null, "reason": "timeout", "detail": null, "unknown": false }
],
"first_ok_at": "2026-09-12T12:04:00.312490",
"last_checked_at": "2026-09-12T18:20:11.874120",
"last_error": "imap: timeout"
}
]
}
],
"used": 4,
"limit": 25,
"services_used": 5,
"services_limit": 15
}Switch a service off
/orgs/{org_id}/watched-domains/{domain_id}/hosts/{host_id}/services/{profile}Pauses the profile and closes any alert it had opened. It stops probing, stops counting against the quota and disappears from the listing, but the decision is remembered, so the next discover will not switch it back on.
curl -X DELETE "https://api.monitor.quathos.com/v1/orgs/$ORG_ID/watched-domains/17/hosts/88/services/webmail" \
-H "Authorization: Bearer $QUATHOS_KEY"What reaches you as an alert
Alerts go out on e-mail and signed webhooks, one per (host, profile): service.web_unreachable, service.webmail_unreachable and service.email_unreachable. Certificates keep their own kinds (tls.expiring, tls.invalid, tls.cert_changed).
Three rules that keep the alert meaningful
unknown (reason: "probe_blind"), not a claim that your server is down.