API reference#
domainsearch answers one question, is this domain registered?, over a plain JSON API. No account, no API key, no cookies. Base URL:
https://domainsearch24.eu/api/v1
How availability is determined#
Every check runs through layered signals, ordered by cost and freshness, and never guesses. The availability status is one of:
| Status | Meaning |
|---|---|
registered |
The domain is taken. |
free |
The registry itself answered "not registered" (RDAP 404). |
unknown |
No signal was available: see the reason field. |
Each answer names its source:
| Source | Layer | Freshness |
|---|---|---|
czds |
ICANN zone files: every delegated name per covered gTLD | ≤ 24 h |
commoncrawl |
Common Crawl web-graph domain set (~120 M domains) | months |
dns |
NS delegation probe: works for every TLD | live |
rdap |
The registry's own RDAP answer: the only source that can assert free |
live |
Two important consequences:
freeis only assertable where RDAP exists. Some ccTLDs (e.g..eu) run no public RDAP; their unregistered domains stay honestlyunknown. Use/tldsto know upfront.freeis a moment-in-time registry answer, not a reservation.
GET /check#
GET /api/v1/check?domains=example.com,example.io[&fast=1]
Checks up to 30 comma-separated domains and returns all results in one
response (extra domains beyond 30 are dropped). Domains must be registrable
names in punycode (IDNs are not auto-encoded). Whole-batch budget: ~9 s;
slow registries yield per-domain unknown and retries are cheap (availability results
are cached server-side: registered 24 h, free 1 h, unknown 10 min).
fast=1 skips RDAP and answers from the local layers only: milliseconds,
but it can assert registered, never free. Use it to pre-filter
candidate lists before confirming the survivors with a full check (or use
streaming and get both in one request).
curl 'https://domainsearch24.eu/api/v1/check?domains=example.com,zqhx.dev'
{
"results": [
{"domain": "example.com", "status": "registered", "source": "czds"},
{"domain": "zqhx.dev", "status": "free", "source": "rdap"}
]
}
GET /check/{domain}#
The curl-friendly single-domain form. Same semantics, bare result object.
curl https://domainsearch24.eu/api/v1/check/example.com
{"domain": "example.com", "status": "registered", "source": "czds"}
GET /check/stream#
GET /api/v1/check/stream?domains=example.com,example.io[&fast=1]
Same input as /check, but the response is NDJSON
(application/x-ndjson): one result object per line, written as each
domain resolves. Local-layer answers arrive in milliseconds while RDAP
confirmations trail in over a few seconds: ideal for progressive UIs.
Line order is completion order, not input order; match on domain. The
stream ends when every domain has answered (budget ~15 s).
curl -N 'https://domainsearch24.eu/api/v1/check/stream?domains=a.com,b.io,c.dev'
GET /bulk/stream#
GET /api/v1/bulk/stream?label=acme[&confirm=1][&tlds=com,io,dev]
The bulk search behind the landing page: ONE label checked across every delegated TLD (~1,450 domains) on a single NDJSON stream.
By default only the fast local layers run (zone files, Common Crawl,
DNS): seconds for the whole TLD space, no registry traffic. A clean local
miss classes as free: no zone entry, no crawl entry, NXDOMAIN. Its
strict status stays unknown: only a registry can formally assert
free: and the registrar checkout is the final word either way.
tlds=com,io,dev restricts the sweep to a comma-separated subset
(unknown TLDs are ignored). DNS probe outcomes are cached server-side for
24 hours, so repeated sweeps are effectively instant.
confirm=1 adds a second phase: RDAP for the still-unknown names on
RDAP-capable TLDs, popular TLDs first, until the ~90 s budget runs out.
Upgrade lines stream with the same domain; a confirm line supersedes
the local one (upgrading assumed-free to registry-confirmed free, or
catching the rare registered-but-undelegated name).
Each line adds a class refining the raw status for filtering:
| class | Meaning |
|---|---|
taken |
Registered. |
free |
No registration found (clean local miss), or registry-confirmed when status is free. |
premium |
Registered with registry status reserved: typically premium/registry-held inventory. |
aftermarket |
Registered, but delegated to a known parking/for-sale marketplace nameserver (heuristic). |
unknown |
No signal either way: e.g. the DNS probe failed, or confirmation is pending. |
The stream opens with {"label":"acme","total":1438} and closes with
{"done":true,"confirm":…,"queued":…,"confirmed":…,"truncated":…}:
truncated: true means the confirmation budget ran out before every
queued name was verified.
curl -N 'https://domainsearch24.eu/api/v1/bulk/stream?label=acme'
Bulk searches are rate limited per IP as whole searches (they already fan out server-side); API keys lift the limit.
GET /tlds#
Every delegated root-zone TLD (per IANA) with capability flags:
{"tlds": [{"tld": "com", "rdap": true, "zone": true}, ...]}
rdap: an RDAP authority is known, sofreeis assertable.zone: a zone-file index is loaded, soregisteredanswers are complete to within ~24 h without any registry lookup.
Cacheable for an hour; the underlying sources change at most daily.
GET /status#
Layer readiness and uptime: also our health check:
{
"ok": true,
"uptime_s": 86400,
"layers": {
"dns": {"enabled": true, "ready": true},
"rdap": {"enabled": true, "ready": true},
"czds": {"enabled": true, "ready": true, "detail": "853 zones indexed"},
"commoncrawl": {"enabled": true, "ready": true}
}
}
Errors#
Errors use one envelope, always JSON:
{"error": {"code": "rate_limited", "message": "anonymous rate limit exceeded; retry later or use an API key"}}
| HTTP | code | When |
|---|---|---|
| 400 | invalid_request |
No domains given. |
| 404 | not_found |
Unknown endpoint. |
| 429 | rate_limited |
Anonymous allowance exhausted: honor Retry-After. |
| 501 | unavailable |
Checking is not configured on this deployment. |
Malformed domains are not request errors: they come back as per-domain
unknown results with a reason, so one bad name never fails a batch.
Rate limits & keys#
Anonymous use is limited per IP, per domain checked (a 30-domain batch costs 30 units): 120 domains/minute with burst headroom of twice that. That is plenty for interactive use.
Calling the API from a service? An API key lifts the limit: request one
at liam@domainsearch24.eu and send it as
Authorization: Bearer <key>.
CORS & OpenAPI#
The API sends Access-Control-Allow-Origin: *: call it straight from the
browser. A machine-readable spec is at
/api/openapi.yaml; this page is also served as plain
markdown at /docs.md for LLM agents (see /llms.txt).