Building a Domain Monitor

This tutorial walks through building an automated domain monitoring system that checks DNS records, tracks WHOIS expiration dates, and monitors SSL certificates — all using Toolkit API endpoints.

What you'll build

A script that monitors a list of domains and alerts you when: - DNS records change (A, MX, NS, TXT) - A domain's WHOIS registration is near expiry - An SSL certificate is about to expire (within 30 days)

Prerequisites

pip install httpx
npm install node-fetch   # if Node.js < 18

Step 1: Check DNS records

Start by resolving all DNS records for a domain and comparing against a baseline:

import httpx
import json
from datetime import datetime

API_KEY = "YOUR_KEY"
BASE_URL = "https://dns.toolkitapi.io/v1"

def get_dns_snapshot(domain: str) -> dict:
    """Get all DNS records for a domain."""
    r = httpx.get(
        f"{BASE_URL}/lookup/all",
        headers={"X-API-Key": API_KEY},
        params={"domain": domain},
    )
    r.raise_for_status()
    data = r.json()

    # Flatten records into a comparable set
    snapshot = {}
    for group in data["results"]:
        records = []
        for rec in group["records"]:
            records.append((rec["value"], rec.get("priority")))
        snapshot[group["type"]] = sorted(records)
    return snapshot

# Take a baseline snapshot
domain = "toolkitapi.io"
baseline = get_dns_snapshot(domain)

# Save baseline to compare later
with open(f"{domain}_baseline.json", "w") as f:
    json.dump(baseline, f, default=str)

print(f"Baseline saved for {domain}")
const API_KEY = "YOUR_KEY";
const BASE_URL = "https://dns.toolkitapi.io/v1";

async function getDnsSnapshot(domain) {
  const params = new URLSearchParams({ domain });
  const r = await fetch(`${BASE_URL}/lookup/all?${params}`, {
    headers: { "X-API-Key": API_KEY },
  });
  const data = await r.json();

  const snapshot = {};
  for (const group of data.results) {
    snapshot[group.type] = group.records.map(rec => ({
      value: rec.value,
      priority: rec.priority,
    }));
  }
  return snapshot;
}

// Compare baseline against current state
async function checkForChanges(domain, baseline) {
  const current = await getDnsSnapshot(domain);
  const changes = [];

  for (const [type, records] of Object.entries(current)) {
    if (!baseline[type]) {
      changes.push(`NEW: ${type} records added`);
      continue;
    }
    const currentValues = JSON.stringify(records.map(r => [r.value, r.priority]));
    const baselineValues = JSON.stringify(baseline[type].map(r => [r.value, r.priority]));
    if (currentValues !== baselineValues) {
      changes.push(`CHANGED: ${type} records modified`);
    }
  }

  for (const type of Object.keys(baseline)) {
    if (!current[type]) {
      changes.push(`REMOVED: ${type} records deleted`);
    }
  }
  return changes;
}

Step 2: Monitor WHOIS expiry

Check domain registration dates and alert when expiry is approaching:

def check_domain_expiry(domain: str, warn_days: int = 30) -> dict | None:
    """Check if a domain is nearing expiry."""
    r = httpx.get(
        f"{BASE_URL}/whois",
        headers={"X-API-Key": API_KEY},
        params={"domain": domain},
    )
    r.raise_for_status()
    data = r.json()

    if not data.get("expires"):
        return None

    expiry = datetime.fromisoformat(data["expires"].replace("Z", "+00:00"))
    days_left = (expiry - datetime.now(expiry.tzinfo)).days

    return {
        "domain": domain,
        "expires": data["expires"],
        "days_left": days_left,
        "registrar": data.get("registrar"),
        "needs_renewal": days_left <= warn_days,
    }
async function checkDomainExpiry(domain, warnDays = 30) {
  const params = new URLSearchParams({ domain });
  const r = await fetch(`${BASE_URL}/whois?${params}`, {
    headers: { "X-API-Key": API_KEY },
  });
  const data = await r.json();
  if (!data.expires) return null;

  const expiry = new Date(data.expires);
  const daysLeft = Math.ceil((expiry - new Date()) / (1000 * 60 * 60 * 24));

  return {
    domain,
    expires: data.expires,
    daysLeft,
    registrar: data.registrar,
    needsRenewal: daysLeft <= warnDays,
  };
}

Step 3: Monitor SSL certificates

Check when TLS certificates expire:

def check_ssl_expiry(domain: str, warn_days: int = 30) -> dict:
    """Check SSL certificate expiry."""
    r = httpx.get(
        f"{BASE_URL}/certificate",
        headers={"X-API-Key": API_KEY},
        params={"domain": domain},
    )
    r.raise_for_status()
    data = r.json()

    return {
        "domain": domain,
        "issuer": data.get("issuer"),
        "days_remaining": data.get("days_remaining", 0),
        "expired": data.get("expired", False),
        "needs_renewal": data.get("days_remaining", 0) <= warn_days and not data.get("expired", False),
    }

Step 4: Put it all together

Combine all checks into a monitoring script:

import sys

domains_to_monitor = [
    "toolkitapi.io",
    "github.com",
    "your-company.com",
]

print(f"Domain Monitor — {datetime.now().isoformat()}\n")

for domain in domains_to_monitor:
    print(f"--- {domain} ---")

    # DNS changes (requires a baseline from Step 1)
    try:
        snapshot = get_dns_snapshot(domain)
        print(f"  DNS: {sum(len(v) for v in snapshot.values())} records across "
              f"{len(snapshot)} types")
    except Exception as e:
        print(f"  DNS: ERROR — {e}")

    # WHOIS expiry
    try:
        whois = check_domain_expiry(domain)
        if whois:
            status = "⚠ EXPIRING" if whois["needs_renewal"] else "✓ OK"
            print(f"  WHOIS: {status} — {whois['days_left']} days left "
                  f"(expires {whois['expires'][:10]})")
    except Exception as e:
        print(f"  WHOIS: ERROR — {e}")

    # SSL expiry
    try:
        ssl = check_ssl_expiry(domain)
        if ssl:
            status = "⚠ EXPIRING" if ssl["needs_renewal"] else "✓ OK"
            print(f"  SSL: {status} — {ssl['days_remaining']} days remaining "
                  f"(issuer: {ssl['issuer']})")
    except Exception as e:
        print(f"  SSL: ERROR — {e}")

    print()

Taking it further

  • Schedule with cron — Run the script daily and send alerts via email or Slack webhook when needs_renewal is true.
  • Track DNS drift — Store baselines in a database and compare daily. Use the propagation endpoint to verify DNS changes have rolled out globally.
  • Add blacklist monitoring — Use the blacklist endpoint to check if your mail server IPs are flagged on any DNSBL.
  • Monitor subdomains — Use the subdomains endpoint to discover new subdomains that appear over time.

Browse all DNS endpoints → Browse WHOIS endpoint →