Skip to content

Domain expiry checks

A domain expiry check reads your domain’s registration record from its registry and alerts you on what the registry says: how long the registration has left, whether the registry is already holding it, who the sponsoring registrar is, and where the nameservers point.

The API and the dashboard call these DNS checks (monitor_dns, /dns/job/...). That name is historical and the pages here use both, but the thing it monitors is the domain registration.

  • Any domain you would lose if a renewal silently failed. The usual cause is an expired card on the registrar account, not a forgotten date.
  • Domains you inherited: from an agency, a former employee, or an acquisition, where nobody is certain who holds the renewal.
  • Domains where a hijack would be expensive. An unannounced registrar or nameserver change is the earliest visible signal of an unauthorised transfer, usually well before the site goes dark.
  • Portfolios. Every monitored domain reports the same three signals, so one alert format covers all of them.

A domain check is paired with an HTTP check. Set monitor_dns: true and SiteQwality provisions one against the registrable domain of the HTTP check’s URL, so https://www.example.com/orders is monitored as example.com.

Each run:

  1. Works down a three-leg chain until one leg returns a registration record for the name. See below.
  2. Records the result, whether or not the lookup worked, along with the expiry date, the registry status codes, the registrar and the nameservers.
  3. Decides whether any of the three signals below is worth an alert, and fans it out through the parent HTTP check’s notification groups.

Cadence is daily. It was weekly until August 2026, which made the warning ladder below impossible to honour: seven days between observations means a domain can be seen at “30 days left” and then next at “expired”.

OrderLegUsed when
1Registry RDAP. The registry’s own RDAP service, located through IANA’s bootstrap registry (about 1,200 TLDs, refreshed daily, with a bundled copy as a fallback). .io and .co run RDAP but are absent from that file, so they are served from two hardcoded entries.Always tried first.
2Port-43 WHOIS. The registry’s own WHOIS server, on the classic port-43 protocol.The TLD has no RDAP service, or RDAP had no record for this name.
3A commercial registration database. A paid third-party source that aggregates registration data.Neither of the first two produced a record.

expiry_source on the check tells you which leg answered: rdap, whois, whoxy, or manual when the date is one you entered yourself. It is null when there is no date at all. Legs 1 and 2 are both the registry’s own answer. Only leg 3 is somebody else’s copy, and it exists to catch the long tail rather than to be the usual path.

RDAP is mandatory for gTLDs and optional for ccTLDs. ICANN’s registry contracts require every gTLD (.com, .org, .dev, and the rest) to run an RDAP service. ccTLD registries are not party to those contracts and are under no obligation, so many run port-43 WHOIS only. IANA’s bootstrap file lists an RDAP service for roughly 1,200 of the 1,438 TLDs in the root.

Reading RDAP and stopping there left a large part of the country-code space with no expiry check at all. A .me domain got nothing.

The WHOIS leg recovers about half of that gap. Measured on 2026-08-09 against 24 ccTLD registries’ own WHOIS servers, these publish an expiry date over port 43: .cn, .dk, .it, .kr, .me, .ru, .se, .sh, .st, .us. The third leg covers what is left, including registries that refuse connections from our address and formats that would otherwise need hand-parsing.

When the registry publishes no expiry date

Section titled “When the registry publishes no expiry date”

Some registries publish no expiry date to anybody, under any protocol. That is policy, not an outage, and no fallback can route around it.

The TLDs we have positively established publish no expiry date:

.am · .at · .be · .de · .eu · .gg · .im · .nl · .no · .nz

A domain on one of these reports:

FieldValue
registry_publishes_expiryfalse
expiry_datenull
expiry_sourcenull
current_statusunknown
last_failure_reasonregistry_publishes_no_expiry

registry_publishes_no_expiry is a state, not a broken check. It is not retried, it will not clear on its own, and it is not an alert. It is the check telling you, in one field, that no amount of waiting will produce a date for this domain.

Everything else the registry does publish still works. Only the expiry ladder is affected: the registrar and nameserver change alerts run off whatever fields that registry returns. .nl is the clearest illustration, because SIDN answers RDAP with a complete record and simply omits the expiration event. .de is the other shape: DENIC publishes no RDAP service at all.

registry_publishes_expiry is true for every TLD not on that list. It is a statement about what we have established, not a guess, so a TLD only lands on the list once we have confirmed it publishes nothing.

For those TLDs, you supply the date. Send it to the check with PUT /dns/job/{dns_job_id}:

Terminal window
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" }'

In the dashboard, the domain card says the TLD publishes no expiry date and offers the same field.

Once it is set:

  • The normal ladder runs against it: 90, 60, 30 and 7 days, then the lapse itself, each rung once per date, exactly as it would against a registry date.
  • expiry_source reads manual.
  • registry_publishes_expiry stays false. It describes the TLD, not your domain.
  • Clear it by sending { "manual_expiry_date": null }.
RungFires whenMessage
90 days90 or fewer days remainexample.com expires in 90 days
60 days60 or fewer days remainexample.com expires in 60 days
30 days30 or fewer days remainexample.com expires in 30 days
7 days7 or fewer days remainexample.com expires in 7 days
LapseThe expiry date is today, or has already passedexample.com expires today, or example.com has expired

Each rung fires once per expiry date. There is no repeat every day, and no second copy of the 30-day warning the following week.

The ladder is fixed. It is not configurable. There is no field for it on the API, no setting in the dashboard, and no way to add or move a rung.

Three behaviours are worth knowing, because none of them is what the table alone suggests:

  • Rungs fire on crossing, not on an exact match. A check that lands at 29 days remaining, having last run at 31, still sends the 30-day warning. A skipped run cannot silently swallow a rung.
  • A rung that was already passed when monitoring started does not fire late. Enable a check on a domain with 45 days left and you get one warning, the 60-day rung, not a burst of 90 and 60. The skipped 90 is marked done and never fires afterwards.
  • A renewal resets the ladder. When the expiry date moves, the record of which rungs have fired is cleared, so next year’s warnings start from a clean slate.

This is the part of the check that the expiry date alone cannot give you, and it is the reason the check reads more than the date.

Every registry publishes a set of EPP status codes on a registration. Most are routine (client transfer prohibited is a lock you want). A few mean the registration is already in trouble, and SiteQwality alerts the first time a domain enters one of them:

Registry stateWhat it meansWhat you should do
auto renew periodThe registration reached its expiry date without being renewed, so the registry renewed it on the registrar’s behalf. The registrar can still cancel that renewal for a refund, typically within 45 days, which deletes the domain.Confirm with your registrar that the renewal was actually paid. This is a real, live risk, not a formality.
redemption periodThe domain was deleted. It is recoverable, usually for about 30 days and usually for a restoration fee well above the renewal price.Contact your registrar today and ask for a redemption restore.
pending deleteRedemption has ended. The domain drops in about five days and cannot be recovered.It is effectively gone. Prepare for the name to be re-registered by someone else.
pending restoreA restore has been requested but is not complete.Follow it through with the registrar until the state clears.
client hold / server holdThe registrar or the registry has pulled the domain out of the zone. The domain does not resolve for anyone right now.Find out why. This is usually a payment dispute or an abuse complaint.

A status alert fires on the transition into a state, so a domain sitting in auto renew period for its whole 45-day window pages you once, not 45 times. If it gets worse (auto renew period becomes pending delete) that is a new state and a new alert.

A registry status does not change the check’s status. A domain in auto renew period still reports good, because its expiry date genuinely is in the future. The alert is the signal. Do not build a dashboard rule that looks only at the status field.

Signal 3: registrar and nameserver changes

Section titled “Signal 3: registrar and nameserver changes”

The check records the sponsoring registrar and the nameserver set on every run and alerts when either changes.

  • Registrar changed. Either a transfer you performed, or one you did not. If you did not, that is a domain transfer away from you and the message says so.
  • Nameservers changed. The delegation moved. This is how a hijack takes your traffic, and it usually happens before anyone notices the registrar changed.

Both are quiet about things that are not really changes:

  • The first check on a domain records the values and never treats that as a change, so enabling monitoring across a portfolio does not page you about every domain at once.
  • A registrar that recases its own name between responses is not a change.
  • Nameservers are lowercased and sorted before comparison, so a registry reordering the list is not a change.
  • Losing every nameserver is a change and does alert. An emptied delegation is how a domain goes dark.
  • Eleven TLDs publish no expiry date at all, so no chain can find one and you have to enter the renewal date yourself. Everything else on the registration still works for them.
  • Platform-hosted hostnames get no domain check. A monitor on *.github.io, *.herokuapp.com, *.vercel.app or any of the roughly 3,200 similar shared suffixes is not paired with a domain check, because the registration belongs to the platform. Reporting GitHub’s renewal date as yours, and firing an alert ladder on it, would be a confident wrong answer.
  • It does not monitor DNS resolution or record values. See the caution at the top of this page.
  • There is no standalone domain check. It is always paired with an HTTP check.
  • Thresholds are not configurable, and neither is the daily cadence.