{"slug": "checking-cctld-availability-without-trusting-one-source-and-what-si-actually-for", "title": "Checking ccTLD availability without trusting one source (and what .si actually sells for)", "summary": "A developer built a free, keyless JSON API that checks .si (Slovenia) domain availability by cross-referencing the ARNES registry record against DNS lookups from two independent resolvers, rather than trusting a single registrar cache. The approach distinguishes registry-only names and wildcard DNS from genuinely unregistered domains, treating SERVFAIL, NoNameservers and timeouts as inconclusive. The accompanying sales index holds 299 recorded .si sales, with the median cited as a better pricing guide than the mean, which is skewed by a few five-figure deals.", "body_md": "Every \"is this domain available\" check you have ever run is a wrapper around someone else's cache. For `.com` that's usually fine — dozens of systems cross-check each other. For a ccTLD it is not fine, and `.si` (Slovenia) is a good example: one letter away from `.ai`, a growing number of short names, and almost no tooling that looks at it.\n\nI built a small free API around it, and the interesting part was not the code — it was realising how many ways a single-source availability check can lie to you.\n\n**1. Stale cache.** A registrar's \"available\" answer is often minutes to hours old. Someone registers the name in between and you find out at checkout.\n\n**2. Wildcard DNS.** Some domains answer *every* query with an A record. A naive DNS check says \"taken\" for names that don't exist, or \"free\" for names that do.\n\n**3. Registry-only records.** A name can exist at the registry with no nameservers at all — NXDOMAIN everywhere, still not yours to register. This is the trap that bites hardest, because DNS looks exactly like an unregistered name.\n\nThe fix is boring: check two independent systems and compare their answers instead of trusting either one.\n\n`.si` is run by ARNES. The registry record tells you existence, registrar, registration and expiry dates, and nameservers. That is the authoritative answer to \"does this exist\", and it is the only source that cannot be faked by DNS weirdness.\n\nI exposed it as plain JSON (no key, no signup):\n\n``` php\nimport json, urllib.request\n\ndef registry(name: str) -> dict:\n    url = f\"https://worthly.si/api/check.php?q={name}\"\n    with urllib.request.urlopen(url, timeout=10) as r:\n        return json.load(r)\n\nrec = registry(\"chauffeurs\")\n```\n\nReal output, trimmed:\n\n```\n{\n  \"domain\": \"chauffeurs.si\",\n  \"availability\": \"registered\",\n  \"note\": \"Registered at the .si registry (ARNES).\",\n  \"registrar\": \"Spaceship, Inc.\",\n  \"registered\": \"2026-10-08\",\n  \"expires\": \"2027-10-08\",\n  \"nameservers\": [\"launch2.spaceship.net\", \"launch1.spaceship.net\"]\n}\n```\n\nNotice what you get for free: the name was registered nine days ago and parked on a registrar's launch nameservers. That is a domain someone bought to flip, and no availability check would have told you that.\n\nDNS answers a different question: *is this name actually in use*. The part people get wrong is treating every failure as \"free\".\n\n``` php\nimport dns.resolver\n\ndef dns_view(name: str) -> str:\n    for qtype in (\"NS\", \"SOA\"):\n        try:\n            dns.resolver.resolve(name, qtype, lifetime=5)\n            return f\"{qtype} present\"\n        except dns.resolver.NXDOMAIN:\n            return \"NXDOMAIN\"          # name does not exist\n        except dns.resolver.NoAnswer:\n            continue                   # exists, no record of this type\n        except dns.resolver.NoNameservers:\n            return \"SERVFAIL/lame\"     # registry knows it, DNS does not answer\n        except dns.resolver.Timeout:\n            return \"timeout\"           # inconclusive — do not call it free\n    return \"no NS/SOA\"\n```\n\n`NXDOMAIN` on **both** NS and SOA is the only DNS answer that supports \"unregistered\". `SERVFAIL`, `NoNameservers` and timeouts are *inconclusive* — and a name that is NXDOMAIN while the registry says \"registered\" is a registry-only name, not an opportunity.\n\nTwo resolvers, compared, is enough. If resolver A says NXDOMAIN and resolver B returns records, you are probably looking at a broken delegation or a wildcard — not a free domain.\n\n`.si` names actually sell for\nThis is where ccTLDs are usually a black box: no comps, so buyers price on vibes and sellers price on hope. The sales index behind the API currently holds **299 recorded .si sales**:\n\nThe gap between median and mean is the whole story: a handful of five-figure deals drag the average up, and if you price against the average you will sit on names for a year. Median is what a typical `.si` actually clears at.\n\nPaired with an appraisal on the same name, the shape is visible. `chauffeurs.si`, a dictionary word parked nine days ago:\n\n```\n{\n  \"method\": \"appraisal v2\",\n  \"domain\": \"chauffeurs.si\",\n  \"value\": { \"low\": 910, \"mid\": 1660, \"high\": 3480, \"currency\": \"USD\", \"confidence\": \"medium\" },\n  \"signals\": { \"category\": \"dictionary\", \"length\": 10, \"dictionary\": true, \"hyphen\": false, \"digit\": false }\n}\n```\n\n`confidence: medium` matters more than the numbers. A dictionary word with a real market gets a range; a random string gets nothing useful, and a tool that pretends otherwise is selling you a number, not information.\n\n``` php\ndef appraise(name: str) -> dict:\n    url = f\"https://worthly.si/api/appraise.php?name={name}\"\n    with urllib.request.urlopen(url, timeout=10) as r:\n        return json.load(r)\n\ndef recent_sales(limit: int = 25) -> dict:\n    url = f\"https://worthly.si/api/sales.php?limit={limit}\"\n    with urllib.request.urlopen(url, timeout=10) as r:\n        return json.load(r)\n```\n\nBoth are free and keyless. The sales endpoint labels each row: venue-reported deals are marked `reported`, venue-confirmed ones `verified`, and asking prices are excluded entirely — a distinction most \"domain sold for $X\" lists quietly ignore.\n\nIf you are checking `.si` names, the useful workflow is: registry record first, DNS second, comps third, and treat anything inconclusive as *unknown* rather than *free*. The API is at [worthly.si/api](https://worthly.si/api) — attribution appreciated, and happy to hear where the appraisal method is wrong.", "url": "https://wpnews.pro/news/checking-cctld-availability-without-trusting-one-source-and-what-si-actually-for", "canonical_source": "https://dev.to/dnwaidev/checking-cctld-availability-without-trusting-one-source-and-what-si-actually-sells-for-4if2", "published_at": "2026-10-17 14:17:10+00:00", "updated_at": "2026-10-17 14:34:28.049598+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["ARNES", ".si", "Spaceship, Inc.", "worthly.si"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/checking-cctld-availability-without-trusting-one-source-and-what-si-actually-for", "markdown": "https://wpnews.pro/news/checking-cctld-availability-without-trusting-one-source-and-what-si-actually-for.md", "text": "https://wpnews.pro/news/checking-cctld-availability-without-trusting-one-source-and-what-si-actually-for.txt", "jsonld": "https://wpnews.pro/news/checking-cctld-availability-without-trusting-one-source-and-what-si-actually-for.jsonld"}}