Solving the "Queen Of" Domain Franchise Availability Check: From Whois Rate-Limiting to RDAP Registry Queries
Overview: The Problem
Ticket t-f860fe03 presented a domain-availability research challenge: determine how many port cities worldwide have available queenof[city].com domains for a proposed boat-tour franchise model. The concept is elegant — each port city gets a local tour operator whose vessel becomes "the Queen of [City]," backed by a standardized brand and booking infrastructure.
The technical challenge wasn't conceptual; it was operational. Checking availability across 130+ port-city domains requires hitting authoritative DNS registries at scale, and the naive approach (raw whois queries) fails spectacularly due to rate-limiting.
Initial Approach: Why Whois Failed
The first implementation in /Users/cb/icloud-jada-ops/ticket-runner/check_queenof_domains.py used Python's whois library against Verisign's WHOIS service. The logic was straightforward:
for city in port_cities:
domain = f"queenof{city}.com"
result = whois.whois(domain)
status = "available" if "No Match" in result else "registered"
This worked for the control test (queenofsandiego.com, which we knew was registered), but produced 130+ "unknown" results. The root cause: Verisign rate-limits WHOIS queries by source IP. After roughly 30-40 consecutive queries, the service begins throttling or dropping responses entirely, returning empty results that our parser interpreted as "unknown."
Why didn't we just retry with backoff? Because WHOIS is a legacy TCP protocol (port 43) with no standard rate-limit signaling. Verisign's behavior is opaque — you can't distinguish between "temporarily throttled" and "actually unknown." Reliability across 130 domains would require complex heuristics and unpredictable delays.
The Solution: RDAP (Registration Data Access Protocol)
We pivoted to RDAP, Verisign's modern HTTP/JSON registry endpoint. RDAP is the ICANN-standardized successor to WHOIS, designed specifically for programmatic registry access:
- HTTP/REST-based: Uses standard HTTP methods and status codes. No custom TCP protocol.
- Standard semantics:
404 = domain not found (available),200 = domain registered. Clear, predictable. - Better rate-limit handling: Returns proper HTTP 429 (Too Many Requests) headers, allowing clients to implement intelligent backoff.
- JSON responses: Structured data, easy to parse and validate.
The refactored implementation queries Verisign's RDAP endpoint at https://rdap.verisign.com/com/v1/domain/:
import requests
def check_domain_availability_rdap(domain):
"""Query Verisign RDAP endpoint for domain availability."""
url = f"https://rdap.verisign.com/com/v1/domain/{domain}"
try:
response = requests.get(url, timeout=5)
if response.status_code == 404:
return "available"
elif response.status_code == 200:
return "registered"
else:
return "unknown"
except requests.RequestException:
return "error"
This simple change yielded clean results: 0 unknowns, proper detection of our control domain as taken, and reliable batch processing across all 130+ port cities.
Infrastructure & File Organization
The ticket runner implementation lives in the Jada ops repository structure:
/Users/cb/icloud-jada-ops/ticket-runner/check_queenof_domains.py— Primary domain-availability checker for franchise cities (San Diego, Shanghai, Singapore, etc.)/Users/cb/icloud-jada-ops/ticket-runner/check_queenof_dream.py— Secondary checker for aspirational "dream destination" cities (smaller, more speculative ports)/Users/cb/icloud-jada-ops/QUEEN-OF-FRANCHISE-DOMAINS-2026-06-04.md— Results report with availability matrix by region/Users/cb/icloud-jada-ops/QUEEN-OF-DREAM-DESTINATIONS-2026-06-04.md— Dream-destination results and notes
Both scripts follow the same pattern: load a CSV of port cities, iterate over each city name, construct the domain string, query RDAP, and aggregate results. Results are written to markdown reports with summary statistics (available count, registered count, error rate) and breakdowns by geographic region.
The scripts integrate with the ticket-runner framework, which manages state via a JSON file and posts results back to the board. The reporter adapter (not detailed here for brevity) consumes the markdown reports and creates ticket updates.
Key Technical Decisions
Why separate scripts for franchise vs. dream destinations? The two cohorts have different characteristics and intended audiences. Franchise domains prioritize major, well-established port cities (high commercial viability). Dream destinations are speculative — beautiful but less touristy ports that might appeal to a niche adventurer demographic. Separating them allows independent analysis and different success criteria.
Why not cache RDAP results? Domain availability can change (someone registers a domain between checks). For a one-time analysis ticket, caching adds complexity without benefit. For production monitoring (e.g., "alert if queenof[X].com becomes available"), we'd implement Redis caching with a 24-hour TTL and periodic refresh jobs.
Why markdown reports instead of structured JSON? The ticket system's reporting adapter expects human-readable output for board display. Markdown renders cleanly in the UI and is easy to audit. Internal tools can parse markdown headers and tables. If machine consumers needed the data, we'd add a JSON export mode.
Error Handling & Reliability
The final implementation includes retry logic for transient network failures:
def check_domain_with_retry(domain, max_retries=3):
"""Check domain availability with exponential backoff on network errors."""
for attempt in range(max_retries):
result = check_domain_availability_rdap(domain)
if result != "error":
return result
wait_time = 2 ** attempt # 1s, 2s, 4s
time.sleep(wait_time)
return "error"
This handles temporary endpoint unavailability without polluting the results with false "errors." After 3 retries with exponential backoff, we mark the domain as "error" and flag it for manual review.
What's Next
With the availability analysis complete, the next phase involves:
- Bulk registration: Purchase available domains for the top franchise targets (likely via a domain registrar API integration)
- DNS provisioning: Create Route53 hosted zones for each domain, configure CNAME records pointing to a centralized booking API
- Monitoring: Deploy continuous RDAP checks on registered domains to detect unauthorized transfers or lapses
- Tier-2 analysis: Run similar checks on alternative TLDs (.tours, .travel, .co) if .com inventory is too limited