← All guides

Guide · Domain probe

Domain expiry monitoring — the WHOIS/RDAP playbook

Every senior engineer has a story about a domain that lapsed despite "auto-renewal". The card on file expired. The renewal invoice went to a privacy proxy and bounced into spam. The registrar locked the renewal pending an ICANN dispute. Domain expiry monitoring is the calendar reminder you actually trust — and, done properly, it doubles as the loudest hijack tripwire you can install for the cost of one daily RDAP query.

Published 2026-05-22 · ~10 min read · StatusPulse Team

Why "auto-renewal" still fails in 2026

The first instinct after a near-miss is always the same: "I'll just turn on auto-renew." Auto-renew is on. It has been on for years. The domain still nearly lapsed. The failure modes live in the spaces around the toggle — all variations of one theme: a payment didn't go through and the email telling you that didn't reach a human who cares.

  • The card on file expired. The founder replaced it six months ago and topped up Stripe, AWS, and GitHub but forgot the registrar that bills once every two years. Renewal fails silently at T-30, T-15, T-1. Nothing in production tells you.
  • The credit limit was reached. A corporate card, a busy month, and the $9.99 renewal gets declined on the same day the AWS invoice clears. The rest of the cycle absorbs fine; the domain quietly does not.
  • The renewal invoice went to a privacy proxy. Whois-privacy services route registrar mail through an opaque alias. Many forwards expire after a year, or the billing emails fail SPF/DKIM against the proxy and land in spam. The notice never reaches anyone with the authority to fix it.
  • An ICANN transfer dispute holds the renewal. A pending transfer-in, a registrant verification (RAA requirement), or a URS complaint locks the domain until the registrar resolves the case. You learn from the EPP status, not from a renewal email.
  • The registrar account was compromised. An attacker SIM-swaps a number, resets the password, transfers contacts, and the renewal fails because the email of record is now under their control.
  • ccTLD with a manual renewal step. Several country registries (some EU and APAC ccTLDs) require an explicit renewal action even with auto-renew enabled — because the registry charges in local currency or requires per-cycle acceptance of updated terms. You have to click a button before T-0.

Polling your homepage doesn't see any of these coming. The signal lives in the registration record — and the protocol for fetching it has quietly improved.

WHOIS vs RDAP — what's the difference, why it matters

WHOIS is the original 1982 protocol: TCP to port 43, send the domain name, get back unstructured plain text in whichever format the registry felt like producing that decade. Verisign for .com returns one shape; Public Interest Registry for .org returns another; Nominet for .uk a third. No schema. Parsing is a regex per registry, and it breaks the day the registry tweaks the indentation.

$ whois example.com
   Domain Name: EXAMPLE.COM
   Registry Domain ID: 2336799_DOMAIN_COM-VRSN
   Registrar WHOIS Server: whois.iana.org
   Registrar URL: http://res-dom.iana.org
   Updated Date: 2024-08-14T07:01:34Z
   Creation Date: 1995-08-14T04:00:00Z
   Registry Expiry Date: 2025-08-13T04:00:00Z
   Registrar: RESERVED-Internet Assigned Numbers Authority
   Registrar IANA ID: 376
   Domain Status: clientDeleteProhibited https://icann.org/epp#clientDeleteProhibited
   Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited
   Domain Status: clientUpdateProhibited https://icann.org/epp#clientUpdateProhibited
   Name Server: A.IANA-SERVERS.NET
   Name Server: B.IANA-SERVERS.NET
   DNSSEC: signedDelegation

RDAP — the Registration Data Access Protocol, formalised by the IETF in RFCs 7480-7484 and mandated by ICANN for all gTLDs since 2019 — replaces all of that with a structured JSON response over HTTPS. One schema, one fetch, one parser.

$ curl -s https://rdap.verisign.com/com/v1/domain/example.com | jq .
{
  "objectClassName": "domain",
  "handle": "2336799_DOMAIN_COM-VRSN",
  "ldhName": "EXAMPLE.COM",
  "status": [
    "client delete prohibited",
    "client transfer prohibited",
    "client update prohibited"
  ],
  "entities": [
    {
      "objectClassName": "entity",
      "handle": "376",
      "roles": ["registrar"],
      "publicIds": [
        { "type": "IANA Registrar ID", "identifier": "376" }
      ],
      "vcardArray": [ "vcard", [ ["fn", {}, "text",
          "RESERVED-Internet Assigned Numbers Authority"] ] ]
    }
  ],
  "events": [
    { "eventAction": "registration",  "eventDate": "1995-08-14T04:00:00Z" },
    { "eventAction": "expiration",    "eventDate": "2025-08-13T04:00:00Z" },
    { "eventAction": "last changed",  "eventDate": "2024-08-14T07:01:34Z" }
  ],
  "nameservers": [
    { "objectClassName": "nameserver", "ldhName": "A.IANA-SERVERS.NET" },
    { "objectClassName": "nameserver", "ldhName": "B.IANA-SERVERS.NET" }
  ],
  "secureDNS": { "delegationSigned": true }
}

Three things matter for monitoring. RDAP returns structured data — read events[].eventDate where eventAction == "expiration" and you're done. RDAP runs over HTTPS, so the response isn't trivially tamperable in transit. RDAP servers expose machine-readable rate-limit headers and stable error codes (RFC 7480 §5.5), so a polite tool backs off cleanly instead of getting blacklisted by a port-43 server.

The right shape in 2026 is RDAP-first, WHOIS-fallback: try RDAP (covers every gTLD and most modern ccTLDs via the IANA bootstrap file at https://data.iana.org/rdap/dns.json), fall back to WHOIS-on-43 for ccTLDs without RDAP, and report a clear "registry doesn't expose expiry" error for the handful that redact the date.

What RDAP actually exposes

Six fields of the RDAP response matter for monitoring. The rest is forensics, not alerting.

  • Registrar name + IANA ID (entities[].vcardArray for the registrar role; publicIds[].identifier for the number). The IANA ID is the durable handle — names change on rebrand, the ID doesn't. Track the ID for drift; surface the name in alerts.
  • Registration / expiration / last-changed dates (events[]). The expiration date drives the alert ladder; the last-changed date is the "anything-moved?" canary.
  • Nameservers (nameservers[].ldhName). The set the registry has delegated authority to. Distinct signal from live DNS drift — this list changes only when someone with registrar credentials updated it.
  • EPP status codes (status[]). Flags ICANN defines for the Extensible Provisioning Protocol — some protective, some catastrophic. Detail below.
  • DNSSEC signed delegation (secureDNS.delegationSigned). True if the registry has a DS record published. Drift here means someone reconfigured DNSSEC at the registry.
  • Registrar abuse contact (entities[].vcardArray for the abuse role). Surface in probe detail so the on-call has it during a suspected hijack.

Two-tier expiry alerting (60 / 14 / 0 days)

The wrong way is a single threshold — "ping me 30 days out" — because by the time you hear it, finance has already escalated something else and the renewal window is half gone. The right way is a ladder, each rung mapped to a different recovery path.

  • Warning at T-60 days. This is the "tell finance" alert. Sixty days is enough runway to reissue a corporate card, get the renewal invoice approved through a procurement queue, and reroute the registrar's billing emails away from the privacy proxy. Severity: low. Route it to a Slack channel, not to PagerDuty.
  • Critical at T-14 days. This is "drop whatever you're doing and click the renew button". Two weeks is the floor for most registrars' standard renewal window before they start adding late fees, and it's also the typical lead time for a manual ccTLD renewal. Severity: medium. Route it to the on-call channel with a name attached.
  • Hard alert at T-0 / past expiry. The registry now reports the domain as expired. Most gTLDs offer a 30-day "redemption grace period" during which DNS resolution may keep working at the registrar's discretion, but you are inside the panic window and the next thing that happens — the registry adding serverHold, or the registrar releasing the domain — is irreversible in under an hour. Severity: high. Page the on-call.

StatusPulse's Domain probe implements the ladder with two configurable thresholds — Degraded at (days) defaults to 30 (move it to 60 if your finance loop is slow), and Expired at (days) defaults to 0. Pair it with the probe's watchers list and you get the routing-by-severity for free: low-severity to email, high-severity to Slack / Teams / SMS. The probe is on the Starter plan and above ($5/mo) — domain expiry probes are not on Free because the registry-query budget is reserved for paid tiers.

Registrar and nameserver drift detection

Expiry alerts handle the boring failure mode. The interesting one — the takeover that puts a business off the internet in forty-five minutes — is the registrar account compromise, and the loudest signal lives in fields you already fetch.

The standard attacker playbook:

  1. Initiate a transfer-out to a registrar in another jurisdiction (sets pendingTransfer).
  2. Update the registrant email of record to one they control.
  3. Update the nameservers (changes nameservers[]).
  4. Wait for the transfer to complete (changes the registrar entity and IANA ID).
  5. Re-point DNS, hijack mail, sell or ransom.

Steps 1, 3, and 4 are visible in RDAP before the attacker controls DNS. An unexpected registrar IANA-ID change between probes is the loudest signal — legitimate transfers are slow, deliberate, and announced; nobody accidentally changes registrar at 03:00 on a Sunday. Nameserver drift in the registry record (distinct from live DNS drift, which a DNS record probe catches separately) means the registrar account was used to re-delegate — exactly what step 3 looks like.

The probe stores the previous IANA ID and nameserver set, compares on every check, and fires an incident on change. False-positive cost is low: legitimate transfers are rare and can be resolved with a one-line note. False-negative cost — silence mid-transfer — is unbounded.

EPP status codes worth tracking

The Extensible Provisioning Protocol — the registry-to-registrar wire format defined in RFCs 5730-5734 — exposes a set of status flags that the registry, the registrar, or both can set on a domain. ICANN documents the full list at icann.org/epp; for monitoring purposes, six are worth knowing by name.

  • clientHold — the registrar has asked the registry to stop publishing the domain's DNS delegation. The most common cause is unpaid invoices; the second most common is a registrar-initiated fraud / abuse response. The domain is, from the public internet's perspective, gone. Page immediately.
  • serverHold — same effect as clientHold, but set by the registry rather than the registrar. Usually an ICANN compliance action, a court order, or a registrar dispute. Even rarer, even louder. Page immediately.
  • pendingTransfer — a transfer-out has been initiated and the five-day ICANN transfer window is running. If you didn't request this, you have about 120 hours to lodge a transfer dispute with your current registrar before the gaining registrar receives the domain. Page immediately.
  • pendingDelete — the registry has scheduled the domain for deletion (typically 30 days after expiry, end of the redemption grace period). If you see this on a domain you intend to keep, you have already missed multiple renewal windows. Page with a "this is bad" runbook.
  • clientTransferProhibited, clientUpdateProhibited, clientDeleteProhibited — the protective trio. You set these deliberately as anti-hijack measures. The probe shouldn't alert when they are present; it should alert when one of them disappears, because an attacker's first move on a compromised account is to lift the lock that's about to block their transfer.

What to alert on, what to ignore

Four rules that survive contact with a real on-call rotation:

  • Page on clientHold, serverHold, pendingTransfer, pendingDelete. Same severity as a site-down HTTP probe. These are the codes that mean "something irreversible is in motion at the registry".
  • Page on registrar IANA-ID change. Distinct alert, distinct severity (treat as critical). The probe stores the previous value and fires on first detected change. Resolve manually after a legitimate transfer.
  • Two-tier expiry: warn at T-60, critical at T-14, page at T-0. Map each rung to a different channel so finance sees the warning and on-call sees the page, not the other way around.
  • Ignore one-off probe failures from RDAP rate limits. Registries rate-limit anonymous RDAP queries (the limits are documented per registry; Verisign publishes theirs, Nominet has tighter limits, some registries return a 429 after as few as 30 queries per hour from a single IP). A single 429 is not a domain incident — it's an RDAP-server hiccup. Alert on N consecutive failures over M hours, not on a single failed query, and back off the probe interval if the registry has been touchy. The default 24-hour interval is well clear of every published limit.

One pattern to avoid: alerting on the privacy-proxy redaction. Most registrars hide the registrant contact behind a privacy service by default — "REDACTED FOR PRIVACY" in the vcardArray is the normal post-2018 state, not an incident. The probe should read the registrar, IANA ID, expiry, status codes, and nameservers — not the registrant.

One more: domain expiry and TLS certificate expiry are different calendars on different clocks. A renewed domain with an expired cert serves nothing. A valid cert on an expired domain serves nothing either. See the SSL certificate monitoring guide for the other expiry, and pair the two for every apex you care about.

Wrap-up

Domain expiry monitoring looks solved — auto-renewal exists, registrars send emails — and then bites every team that hasn't been bitten yet. The failure modes are mundane (dead card, spam-bucketed invoice, ccTLD with a manual step); the recovery is brutal (30-day redemption penalty if you're lucky, irreversible release if you aren't). RDAP-first probing with a 60 / 14 / 0-day ladder turns the calendar problem into a countdown that lands in the right inbox at each step.

The same probe, with drift detection on the IANA ID and the registry nameserver list, doubles as the highest-signal hijack tripwire you can install. Steps one, three, and four of an account takeover are all visible in RDAP before the attacker controls a single authoritative DNS answer. EPP codes (clientHold, serverHold, pendingTransfer) close the loop. Get the ladder, drift, and codes wired into one probe per apex and the domain class of incident collapses from "we found out Monday when the site wouldn't load" to "Slack pinged finance two months ago".

Try StatusPulse's Domain probe

5 probes free; Domain probe from Starter ($5/mo). US or EU host — you choose.