Engineering

Domain Monitoring Webhooks: Route WHOIS, DNS and SSL Alerts Where Your Team Already Works

Email alerts are fine until they drown in a shared inbox. Domain monitoring webhooks POST structured JSON the moment WHOIS, DNS, expiry or SSL posture changes — so Slack, PagerDuty, Jira or your SIEM can open a ticket before customers notice.

October 5, 202611 min readEngineering · Monitoring · Webhooks · SIEM

Introduction

Most teams discover domain problems the hard way: a site that stops resolving, a certificate that expired overnight, or a registrar change nobody approved. Polling WHOIS and DNS on a cron job can catch some of that — but it burns API credits, adds detection lag equal to your interval, and forces you to build diff logic, storage and alerting yourself.

WhoisJSON Domain Monitoring flips the model. You register critical domains once, choose which layers to watch, and attach a webhook URL. When a confirmed change or threshold warning fires, WhoisJSON sends an HTTPPOST with a typed JSON payload. Your application decides severity, opens a ticket, or pages on-call.

This guide is the integration playbook: event types, payload shapes, Node.js and Python receivers, and how to route alerts without recreating the monitoring service. It complements the security-team baseline (what to watch) and the expiry detection guide (lifecycle stages) without repeating endpoint tutorials.

Why Webhooks Beat Polling and Inbox-Only Alerts

  • Lower quota burn. Continuous checks run on WhoisJSON infrastructure. You pay for monitoring slots — not for polling every domain every hour from your workers.
  • Faster mean time to detect. Changes are compared against a stored baseline with confirmation logic. You receive an event when the diff is real, not when your next cron happens to run.
  • Actionable automation. A JSONPOST plugs into Slack Incoming Webhooks, Microsoft Teams, PagerDuty Events API, custom SOAR playbooks, or a thin Express/Flask handler that creates Jira issues.
  • Separation of concerns. Product engineers keep domain posture out of the critical request path. Security and ops own the receiver and severity rules.

Polling vs Built-In Monitoring

DimensionDIY pollingWhoisJSON monitoring + webhook
Detection lagEqual to your cron intervalContinuous checks with change confirmation
Diff / baseline storageYou build itIncluded
Credit usageScales with domains × frequencySlot-based monitoring
Alert deliveryEmail script you maintainEmail and/or webhook POST
Best forAd-hoc scripts, one-off auditsProduction portfolios and SIEM ingestion
Keep API polling for on-demand enrichment, CI gates and investigations. Use monitoring webhooks for “tell me when something changes on domains I already own.”

Event Types You Can Subscribe To

Each monitor can enable one or more alert categories. Webhook deliveries use a code type | field so a single endpoint can branch safely.

typeFires whenTypical action
whois_changeConfirmed WHOIS/RDAP drift (registrar, status, nameservers, dates, contacts when present)Security review — possible hijack or authorized transfer
dns_changeConfirmed DNS record drift vs previous snapshotOps review — cutover vs unauthorized NS/A/MX change
expiration_warningDays until domain expiry ≤ your threshold (default often 30)Renewal ticket; escalate under 7 days
ssl_expiration_warningDays until TLSvalid_to ≤ SSL thresholdCert renew runbook; page if < 7 days on production

How to Configure a Monitoring Webhook

  1. Create or sign in to your WhoisJSON account and open Domain Monitors.
  2. Add the domain (apex or critical hostname your team owns).
  3. Enable the alert layers you care about: WHOIS changes, DNS changes, domain expiry, SSL expiry.
  4. Set thresholds for expiry warnings (domain days / SSL days).
  5. Enable the webhook channel and paste an HTTPS URL that acceptsPOST JSON (for examplehttps://ops.example.com/hooks/whoisjson).
  6. Optionally keep email as a backup channel for humans who are not on-call.
Plan note: Email alerts are available on all plans. Webhook notifications (HTTP POST with JSON payloads) are available on paid plans — see domain monitoring and pricing. Free plans include a monitoring slot with email; upgrade when you need SIEM or Slack automation.

Webhook Payload Reference

Every delivery is a JSON body. The envelope always includes code type | and code timestamp | , plus event-specific fields.

whois_change

whois_changeJSON
{
  "type": "whois_change",
  "timestamp": "2026-10-05T08:14:22.101Z",
  "domain": "example.com",
  "changes": {
    "nameserver": {
      "previous": ["ns1.old-dns.net", "ns2.old-dns.net"],
      "current": ["ns1.new-provider.com", "ns2.new-provider.com"]
    },
    "registrar": {
      "previous": { "name": "Old Registrar Inc" },
      "current": { "name": "New Registrar LLC" }
    }
  },
  "currentWhois": { "...": "full WHOIS JSON snapshot" }
}

dns_change

dns_changeJSON
{
  "type": "dns_change",
  "timestamp": "2026-10-05T08:16:03.550Z",
  "domain": "example.com",
  "previousDns": { "A": ["203.0.113.10"], "NS": ["ns1.old-dns.net"] },
  "currentDns": { "A": ["198.51.100.20"], "NS": ["ns1.new-provider.com"] }
}

expiration_warning

expiration_warningJSON
{
  "type": "expiration_warning",
  "timestamp": "2026-10-05T09:00:01.000Z",
  "domain": "example.com",
  "daysRemaining": 28,
  "expirationDate": "2026-11-02T00:00:00.000Z"
}

ssl_expiration_warning

ssl_expiration_warningJSON
{
  "type": "ssl_expiration_warning",
  "timestamp": "2026-10-05T09:05:44.220Z",
  "domain": "example.com",
  "daysRemaining": 12,
  "expirationDate": "2026-10-17T12:00:00.000Z",
  "certificateInfo": {
    "issuer": { "CN": "Example CA", "O": "Example CA Inc" },
    "valid_from": "2025-10-17T12:00:00.000Z",
    "valid_to": "2026-10-17T12:00:00.000Z"
  }
}

Expiry warnings are rate-limited to roughly one alert per domain per day while the threshold remains crossed — so renewals do not spam your webhook every check cycle. For lifecycle detail, see how to detect domain expiry.

Node.js: Express Receiver

Acknowledge quickly with HTTP 200, then process asynchronously if work is heavy. Validate code type | before acting.

webhookReceiver.jsJavaScript
const express = require('express');
const app = express();
app.use(express.json({ limit: '1mb' }));

const SEVERITY = {
  whois_change: 'high',
  dns_change: 'high',
  expiration_warning: 'medium',
  ssl_expiration_warning: 'medium',
};

app.post('/hooks/whoisjson', async (req, res) => {
  const event = req.body || {};
  if (!event.type || !event.domain) {
    return res.status(400).json({ error: 'invalid payload' });
  }

  // ACK first — then enrich / notify
  res.status(200).json({ ok: true });

  const severity = SEVERITY[event.type] || 'info';
  if (event.type === 'expiration_warning' && event.daysRemaining <= 7) {
    // escalate
  }
  if (event.type === 'ssl_expiration_warning' && event.daysRemaining <= 7) {
    // escalate
  }

  await routeAlert({
    severity,
    domain: event.domain,
    type: event.type,
    event,
  });
});

async function routeAlert({ severity, domain, type, event }) {
  // Slack, PagerDuty, Jira, SIEM HTTP collector...
  console.log(`[${severity}] ${type} on ${domain}`, JSON.stringify(event).slice(0, 200));
}

app.listen(8080);

Python: FastAPI Receiver

webhook_receiver.pyPython
from fastapi import FastAPI, BackgroundTasks, HTTPException
from pydantic import BaseModel, Field
from typing import Any, Optional

app = FastAPI()

class MonitorEvent(BaseModel):
    type: str
    domain: str
    timestamp: Optional[str] = None
    daysRemaining: Optional[int] = None
    changes: Optional[dict[str, Any]] = None
    currentWhois: Optional[dict[str, Any]] = None
    previousDns: Optional[dict[str, Any]] = None
    currentDns: Optional[dict[str, Any]] = None
    certificateInfo: Optional[dict[str, Any]] = None
    expirationDate: Optional[Any] = None

def handle_event(event: MonitorEvent) -> None:
    severity = "high" if event.type in {"whois_change", "dns_change"} else "medium"
    if event.daysRemaining is not None and event.daysRemaining <= 7:
        severity = "critical"
    # POST to Slack / SIEM here
    print(severity, event.type, event.domain)

@app.post("/hooks/whoisjson")
async def whoisjson_hook(event: MonitorEvent, background: BackgroundTasks):
    if event.type not in {
        "whois_change",
        "dns_change",
        "expiration_warning",
        "ssl_expiration_warning",
    }:
        raise HTTPException(status_code=400, detail="unknown type")
    background.add_task(handle_event, event)
    return {"ok": True}

Severity Routing Patterns

One webhook URL does not mean one channel. Branch inside the receiver:

  • whois_change / dns_change on production apex → PagerDuty or high-priority Slack channel (possible hijack or bad cutover). Cross-check with the hijacking signals guide.
  • expiration_warning with daysRemaining > 14 → create a renewal ticket; no page.
  • expiration_warning or SSL warning with daysRemaining ≤ 7 → page on-call for customer-facing hostnames.
  • Staging / sandbox domains → low-priority channel or suppress unless WHOIS registrar changes.
Tip: Store a small allowlist of critical domains in your receiver. The same WhoisJSON account can monitor many names; only escalate the ones that would take production down.

Limits and Best Practices

  • Expose only HTTPS endpoints. Reject non-TLS receivers in production.
  • Return 2xx quickly. Do heavy SIEM enrichment in a queue or background task so WhoisJSON does not wait on your downstreams.
  • Treat unknowntype values as non-fatal — log and ignore so future event types do not break your handler.
  • Deduplicate ondomain + type + calendar day for expiry events if you fan out to multiple systems.
  • Keep email enabled as a fail-safe while you validate the webhook path.
  • Pair continuous monitoring with deploy-time checks — see CI/CD domain health checks — so misconfigurations fail before traffic shifts.
  • For brand lookalikes (domains you do not own yet), use brand protection monitoring; webhooks here target domains you already control.

FAQ

What is a domain monitoring webhook?

An HTTPS endpoint you own that receives a JSON POST when WhoisJSON detects WHOIS drift, DNS drift, domain expiry risk or SSL expiry risk on a monitored domain.

Which event types does WhoisJSON send?

whois_change, dns_change, expiration_warning and ssl_expiration_warning — controlled per monitor in the dashboard.

Do I still need to poll the WHOIS API?

For continuous change detection on owned domains, no. Keep API lookups for investigations, CI gates, enrichment and one-off audits.

Are webhooks available on the free plan?

Email alerts are available on all plans. Webhook POST delivery is available on paid plans. See domain monitoring for current channel details.

Can I send alerts to Slack or a SIEM?

Yes. Point the webhook at a thin adapter that maps the payload to Slack Incoming Webhooks, PagerDuty, Elastic, Splunk HEC or your SOAR collector.

How is this different from the security monitoring baseline article?

The security baseline explains what signals matter. This article is the engineering integration: payloads, receivers and routing.

Put Domain Alerts in Your Incident Path

Add monitors for production domains, attach a webhook, and route WHOIS, DNS, expiry and SSL events to Slack or your SIEM — without building a poller.

Get API KeyDomain Monitoring
Domain Monitoring Webhooks

Stop Polling. Start Receiving Events.

Wire WHOIS, DNS, expiry and SSL alerts into Slack or your SIEM with one HTTPS endpoint — monitoring slots included with WhoisJSON plans.

4 event typesJSON webhook POSTNode.js & Python samplesFree monitoring slot