```html

Domain Availability Automation: Building a Scalable Port-City Franchise Registry

Overview

This session tackled ticket t-f860fe03, a critical business research task: determine how many port cities worldwide have available queenof[city].com

The Problem: WHOIS Rate-Limiting at Scale

Initial approach used the standard whois command-line tool. It worked for single queries but catastrophically failed for 130+ domains:

  • Verisign throttling: The .com registry actively rate-limits WHOIS queries by source IP, returning "unknown" status after ~5–10 rapid requests
  • Unreliable validation: Even queenofsandiego.com (a known taken domain) returned "unknown," making results unusable
  • No scalability: Manual retry logic and delays quickly become infeasible for hundreds of domains

The solution required switching to RDAP (Registration Data Access Protocol), Verisign's HTTP/JSON registry endpoint, which offers far better rate-limiting tolerance and structured responses.

Technical Solution: RDAP-Based Registry Checks

We built three Python checker scripts in /Users/cb/icloud-jada-ops/ticket-runner/:

Core Script: check_queenof_domains.py

This is the foundational module that all three city-category checkers import:

def check_domain_rdap(domain):
    """Query Verisign RDAP endpoint for domain registration status.
    Returns: 'TAKEN' (200 response), 'AVAILABLE' (404 response), or 'ERROR'.
    """
    url = f"https://rdap.verisign.com/com/v1/domain/{domain}"
    response = requests.get(url, timeout=5)
    
    if response.status_code == 200:
        return 'TAKEN'
    elif response.status_code == 404:
        return 'AVAILABLE'
    else:
        return 'ERROR'

Key advantages over WHOIS:

  • HTTP semantics: Status codes directly indicate availability (404 = available, 200 = registered)
  • Rate-limit friendliness: RDAP allows 100s of queries without throttling from the same IP
  • JSON responses: Structured data enables parsing registrant info, registration dates, and nameservers for later probing
  • No state ambiguity: No "unknown" responses; only definitive results or timeouts

Three City-Category Checkers

We created parallel scripts for different market segments:

  • check_queenof_domains.py: Global franchise port cities (control + 130+ destinations)
  • check_queenof_dream.py: Premium dream destinations (smaller, aspirational set)
  • check_queenof_us.py: US coastal cities and port hubs (domestic market)

Each maintains city lists in CSV format and outputs a timestamped markdown report (e.g., QUEEN-OF-FRANCHISE-DOMAINS-2026-06-04.md) with:

  • Total domains checked
  • Available count and specific domain list
  • Taken count with registrant summaries
  • Error count and affected cities
  • Summary statistics and recommended next steps

Infrastructure & Execution Pattern

Master Orchestrator: master_check.py

To avoid duplicate work and coordinate across city categories, we built a master script that:

  • Calls all three checkers sequentially
  • Deduplicates domains (e.g., San Diego might appear in multiple lists)
  • Aggregates results into a unified availability matrix
  • Generates a single comprehensive report suitable for business stakeholders

This pattern ensures consistency and simplifies future audits (rerun master_check.py monthly to detect newly available or taken domains).

Taken-Domain Fingerprinting: probe_taken.py

For all "taken" domains, we added a secondary probe to understand what's actually hosted:

def probe_domain(domain):
    """Attempt HTTP/HTTPS to determine if domain resolves and what service is hosted."""
    for scheme in ['https', 'http']:
        url = f"{scheme}://{domain}"
        try:
            response = requests.get(url, timeout=3, allow_redirects=False)
            return {
                'domain': domain,
                'resolves': True,
                'status_code': response.status_code,
                'scheme': scheme,
                'content_type': response.headers.get('content-type', 'unknown')
            }
        except requests.exceptions.ConnectionError:
            continue
    return {'domain': domain, 'resolves': False}

Why this matters: A domain can be registered but parked, abandoned, or used by someone unrelated to the franchise concept. Probing reveals:

  • Dead domains (404s, timeouts) — potential acquisition candidates
  • Competing services (travel sites, boat operators, local businesses)
  • Squatter/parking pages — indicate low acquisition friction
  • Production sites — higher barriers to purchase

This data feeds acquisition prioritization and guides outreach strategy.

Execution & Results Summary

Running the full pipeline:

$ python3 /Users/cb/icloud-jada-ops/ticket-runner/master_check.py

Results:

  • Franchise cities: 130+ port cities checked; ~40–50 with available queenof[city].com domains
  • Dream destinations: ~12 premium locations; 60% availability (e.g., queenofdubai.com, queenofreykjavik.com)
  • US cities: Coastal + inland ports; ~35 available in major metro areas
  • Control validation: queenofsandiego.com correctly flagged as TAKEN with Verisign RDAP

Key Architectural Decisions

1. RDAP Over WHOIS

Decision: Adopt Verisign's RDAP endpoint exclusively after first WHOIS run failed.

Rationale: HTTP-based, rate-