Domain Availability Auditing at Scale: Solving the "Queen Of" Franchise Validation Problem

Ticket t-f860fe03 presented a deceptively simple requirement with significant technical complexity: determine how many port cities worldwide have available queenof[city].com domain names for a franchise concept. The naive approach—using whois CLI tools—hit rate-limiting issues at scale. This post covers how we pivoted to RDAP (Registration Data Access Protocol) for reliable, high-throughput domain validation.

The Problem: Whois Rate Limiting at Scale

Our initial implementation in /Users/cb/icloud-jada-ops/ticket-runner/check_queenof_domains.py used the Python whois library against Verisign's authoritative registry. For small lookups, this works perfectly—we confirmed queenofsandiego.com as registered. However, when querying ~130 port cities globally, Verisign's IP-based rate limiting kicked in hard:

  • Queries returned "unknown" status instead of authoritative YES/NO responses
  • The rate limiting applied indiscriminately—even our control domain (queenofsandiego.com) showed as unknown mid-run
  • Exponential backoff became impractical; a single audit would take hours

This is a well-known limitation of whois: it's a legacy TCP protocol with no standardized rate-limiting mechanism. ISPs and registrars throttle by source IP when detecting automated queries.

Technical Architecture: Migration to RDAP

RDAP (RFC 7480) is Verisign's modern HTTP/JSON replacement for whois. Key advantages for our use case:

  • HTTP Status Codes as Authority: 404 Not Found = domain available; 200 OK with domain object = registered
  • Rate Limiting via HTTP Standards: Respects Retry-After headers and returns proper 429 Too Many Requests instead of silent throttling
  • JSON Responses: Structured data eliminates regex parsing fragility
  • Higher Throughput: Designed for programmatic bulk queries; Verisign's RDAP endpoint is significantly less throttled than whois

Implementation Details

We rewrote check_queenof_domains.py to use RDAP exclusively. The core lookup function:

def check_domain_rdap(domain_name, timeout=5):
    """
    Query Verisign RDAP endpoint for .com/.net domains.
    Returns: 'available' | 'registered' | 'error'
    """
    rdap_url = f"https://rdap.verisign.com/com/v1/domain/{domain_name}"
    try:
        response = requests.head(rdap_url, timeout=timeout, allow_redirects=False)
        if response.status_code == 404:
            return 'available'
        elif response.status_code == 200:
            return 'registered'
        elif response.status_code == 429:
            # Handle rate limiting gracefully
            retry_after = int(response.headers.get('Retry-After', 5))
            time.sleep(retry_after)
            return check_domain_rdap(domain_name, timeout)
        else:
            return 'error'
    except requests.Timeout:
        return 'error'
    except Exception as e:
        logger.error(f"RDAP lookup failed for {domain_name}: {str(e)}")
        return 'error'

Key design decisions:

  • HEAD Requests: We use HTTP HEAD instead of GET to minimize bandwidth and response time. The status code tells us everything needed.
  • Retry Logic: Explicit handling of 429 Too Many Requests with backoff respects Verisign's rate limits gracefully.
  • Timeout Configuration: 5-second timeout per request prevents hanging on slow registry responses.
  • Error Categorization: Distinguishing 'error' from 'available'/'registered' lets downstream reporting identify data quality issues.

Port City Data Source and Execution

We curated a list of ~130 major port cities globally (Miami, Barcelona, Singapore, Sydney, etc.) and iterated through systematic domain checks. The main audit loop:

port_cities = [
    "miami", "barcelona", "singapore", "sydney", "dubai", "vancouver",
    "hong-kong", "london", "hamburg", "dubai", "shanghai", ...
]

results = {
    'available': [],
    'registered': [],
    'error': []
}

for city in port_cities:
    domain = f"queenof{city}.com"
    status = check_domain_rdap(domain)
    results[status].append(domain)
    logger.info(f"{domain}: {status}")

Results were written to /Users/cb/icloud-jada-ops/QUEEN-OF-FRANCHISE-DOMAINS-2026-06-04.md and /Users/cb/icloud-jada-ops/QUEEN-OF-DREAM-DESTINATIONS-2026-06-04.md for archival and reporting.

Validation and Control Testing

Before reporting results, we validated the RDAP implementation against known domains:

  • Control (Registered): queenofsandiego.com200 (✓ correctly identified as registered)
  • Control (Test): Random domain `zxcvqwerty12345.com → 404 (✓ correctly identified as available)

Zero ambiguity. RDAP's HTTP semantics eliminated the "unknown" status problem entirely.

Board Integration and Ticket Resolution

We identified the ticket system's board state stored in S3 and fetched via CloudFront. The reporter adapter needed authentication to POST results back to t-f860fe03. After verifying AWS credentials and board writer permissions, results were summarized as:

  • Available domains: [list of cities where queenof[city].com is open]
  • Registered domains: [list already taken, mostly by existing operators]
  • Errors: [minimal; only network timeouts on a few lookups]

Infrastructure and Deployment Notes

No infrastructure changes were required for this audit. The solution leverages:

  • Verisign RDAP Endpoint: https://rdap.verisign.com/com/v1/domain/{domain} — publicly available, no authentication needed
  • Local File Storage: Results written to ticket-runner working directory for audit trails
  • Ticket System: Results posted via existing board adapter authenticated against the operational infrastructure

No S3 bucket changes, no Route53 updates, no CloudFront cache invalidations were necessary.

Key Lessons and Patterns

Protocol Evolution Matters: Whois predates automated querying at scale. RDAP