Domain expiry quickstart
By the end of this guide your domain’s registration is being read once a day, you will know how to tell a healthy result from a stale one, and you will know what to do if your TLD is one of the ten that publish no expiry date.
Prerequisites
Section titled “Prerequisites”- An existing HTTP check. If you do not have one, follow the HTTP checks quickstart.
- The HTTP 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, then Settings.
-
Toggle Monitor DNS on, and save.
The domain check is provisioned immediately, but it runs on its own daily schedule with a flexible window of up to four hours, so the first result may take a few hours to appear rather than landing on save.
# On an existing checkcurl -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 }'Or at create time:
curl -X POST https://api.siteqwality.com/http/job \ -H "Authorization: Bearer $SITEQWALITY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "friendly_name": "API homepage", "method": "GET", "uri": "https://api.example.com/", "monitor_tls": true, "monitor_dns": true, "timeout_ms": 15000, "run_interval_seconds": 600, "group_notification_ids": [] }'The HTTP check’s response carries the paired check’s id as dns_job_id.
2. Read the result
Section titled “2. Read the result”The HTTP check page shows a DNS sub-card with the current status, the registrable domain being monitored, and the expiry date once the first run completes.
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 its own copy of 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. That is correct: 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, used when the registry gave us nothing, and is worth a second look before you act on it.manualis a date somebody at your company typed in. See where the date comes from.expiry_datemay differ by a day from your registrar’s control panel. SiteQwality reads the registry’s date, not the registrar’s. That is expected.
If last_failure_reason is ever set, the registry fields around it are the last known values rather than current ones, because a run that could not reach the registry deliberately leaves them alone. The reference covers the distinction between the check and one run of it.
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.appsucceeds and creates the HTTP check, but quietly pairs no domain monitor, because the registration forvercel.appbelongs to Vercel. Turning it on afterwards withPUT /http/job/{id}is refused explicitly:400 myapp.vercel.app is hosted on vercel.app, which is a shared platformdomain. Domain-expiry monitoring needs a domain you register yourself. -
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”Eleven TLDs publish no expiry date to anybody, under any protocol, because their registries have decided not to:
.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 and nothing to retry. Registrar and nameserver change alerts still work normally.
The fix is to tell SiteQwality the date yourself.
-
Open the HTTP check and find the domain card. On these TLDs it says the registry publishes no expiry date, instead of showing a countdown.
-
Enter your renewal date and 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. Either way the updated check comes back in the response.
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”You do not need to do anything to receive alerts: they go to the same notification groups as the parent HTTP check. What arrives 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 |