Domain expiry quickstart
This turns on DNS monitoring for an existing HTTP check. The check’s URL must be on a domain you register yourself: hosts on shared platform suffixes (*.github.io, *.herokuapp.com, *.vercel.app) cannot be monitored this way. See step 3.
1. Turn it on
Section titled “1. Turn it on”-
Open the HTTP check and choose Edit monitor.
-
Under Optional checks, turn Monitor DNS on and click Save changes. New HTTP monitors have it on already.
With an API key exported as SITEQWALITY_API_KEY, and $JOB_ID set to the HTTP check’s id:
curl -X PUT https://api.siteqwality.com/http/job/$JOB_ID \ -H "Authorization: Bearer $SITEQWALITY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "monitor_dns": true }'New HTTP checks have it on unless created with "monitor_dns": false.
The HTTP check’s response carries the paired check’s id as dns_job_id; the API steps below use it as $DNS_JOB_ID.
The check runs on a daily schedule with a flexible window of up to four hours, so the first result may take a few hours to appear.
2. Read the result
Section titled “2. Read the result”The HTTP check page shows a Domain tile with the status and days until expiry. The Domain Registration section of the Details panel shows the registrable domain being monitored and, once the first run completes, the expiry date.
curl https://api.siteqwality.com/dns/job/$DNS_JOB_ID \ -H "Authorization: Bearer $SITEQWALITY_API_KEY"{ "id": "...", "http_job_id": "...", "current_status": "good", "domain": "example.com", "expiry_date": "2027-03-14T00:00:00Z", "expiry_source": "rdap", "manual_expiry_date": null, "registry_publishes_expiry": true, "domain_status": ["client transfer prohibited"], "grace_states": [], "registrar": "Example Registrar, Inc.", "nameservers": ["ns1.example-dns.com", "ns2.example-dns.com"], "last_run_at": "2026-08-08T04:11:07Z", "last_status_change_at": null, "last_failure_reason": null, "last_failure_at": null, "created_at": "2026-08-07T09:02:44Z"}For history, GET /dns/job/{dns_job_id}/results?limit=50 returns recent runs newest first, each with its own status, failure_reason and what that run saw.
Five things to check on that first result:
domainis the registrable domain, not the hostname you monitor.https://www.example.com/ordersis monitored asexample.com, because registries hold registrations, not hostnames.current_statusisgood,expiredorunknown.unknownis not an error state on its own. See the status table.grace_statesis empty, and that is the field to watch. A non-empty list means the registration is in trouble no matter how far away the date reads. See the registry states.expiry_sourcesays who gave you the date.rdapandwhoisare the registry’s own answer.whoxyis a commercial database, worth a second look before you act on it.manualis a date you entered. See where the date comes from.expiry_datemay differ by a day from your registrar’s control panel. Site Qwality reads the registry’s date, not the registrar’s.
If last_failure_reason is set, the registry fields around it are last-known values rather than current ones. See the check and a run of the check.
3. If nothing appears
Section titled “3. If nothing appears”-
Check that a domain monitor was created at all. Fetch the HTTP check and look for
dns_job_id. If it isnull, none was provisioned. -
If the URL is on a shared platform suffix, that is expected. A create with
monitor_dns: trueonmyapp.vercel.appcreates the HTTP check but pairs no domain monitor, because the registration forvercel.appbelongs to Vercel. Turning it on afterwards withPUT /http/job/{id}is refused with an error saying the host is on a shared platform domain. -
If the status is
unknown, read the failure reason.GET /dns/job/{id}/resultsreturnsfailure_reasonper run.registry_publishes_no_expiryis not a failure and needs step 4. Everything else is a real lookup problem and is listed in the reference.
4. If your TLD publishes no expiry date
Section titled “4. If your TLD publishes no expiry date”Ten TLDs publish no expiry date to anybody, by registry policy:
.am · .at · .be · .de · .eu · .gg · .im · .nl · .no · .nz
A domain on one of them reports registry_publishes_expiry: false, expiry_date: null, current_status: unknown and last_failure_reason: "registry_publishes_no_expiry". The check is not broken: no source has the date, so there is nothing to wait for. Registrar and nameserver change alerts still work. Enter the date yourself.
-
Open the HTTP check and find Domain Registration in the Details panel. On these TLDs it says the registry publishes no expiry date, instead of showing a date.
-
Under Enter the renewal date, pick the date and click Save.
curl -X PUT https://api.siteqwality.com/dns/job/$DNS_JOB_ID \ -H "Authorization: Bearer $SITEQWALITY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "manual_expiry_date": "2027-03-01T00:00:00Z" }'Send { "manual_expiry_date": null } to clear it.
From then on the check behaves like any other: warnings at 90, 60, 30 and 7 days, then on the lapse, each rung once. expiry_source reads manual.
5. Know what an alert will look like
Section titled “5. Know what an alert will look like”Alerts go to the parent HTTP check’s notification groups. Each is one of five messages.
| Trigger | Headline |
|---|---|
| A ladder rung (90, 60, 30 or 7 days) | example.com expires in 30 days |
| The registration lapses | example.com expires today, or example.com has expired if it lapsed before monitoring saw it |
| The registry starts holding the domain | example.com is in auto renew period |
| The sponsoring registrar changes | example.com changed registrar |
| The nameserver delegation changes | example.com changed nameservers |
A registry state alert can arrive while the expiry date still reads years away: the registry renewed the domain automatically and the registrar can still hand it back. The overview explains this auto-renew trap. Maintenance windows do not hold domain alerts.