Skip to content

HTTP API

ds can answer the same checks over HTTP, for a web front end or anything else that would rather call an API than shell out. It is in every released binary and package — --serve is there in the ds you already have, and it stays off until you ask for it.

ds --serve                    # http://127.0.0.1:8080

Building it out is still possible: cargo build --release --no-default-features drops the serve feature, and with it --serve and every server option below.

Endpoint What it does
GET /v1/check?name=…&tld=… checks the names and returns the same JSON ds --json prints
GET /healthz {"status":"ok","version":"…"}, never touches a registry
$ curl -s 'http://127.0.0.1:8080/v1/check?name=apple&tld=com,net'
[
  {"domain":"apple.com","tld":"com","status":"taken","method":"rdap","elapsed_ms":511,
   "price":{"currency":"USD","register":14.98,"renew":18.48,"registrars":1}},
  {"domain":"apple.net","tld":"net","status":"taken","method":"rdap","elapsed_ms":535,
   "price":{"currency":"USD","register":14.98,"renew":18.58,"registrars":1}}
]

name and tld may both be repeated or comma separated, and tld takes the same popular and rdap keywords --tld does. With no tld, a dotted name is a whole domain and a bare label means .com — again as on the command line. Results come back in the order asked for. Anything rejected is a 4xx with {"error": "…"}; Retry-After comes with a 429.

status is available, taken, unknown or private, and both of the statuses that are not a plain yes or no mean here exactly what they mean on the command line. An inconclusive lookup is unknown, and a response holding one is sent Cache-Control: no-store, since it is a lookup that failed rather than an answer to keep. A name in a brand or reserved zone is private, with the reason in note — a settled fact out of a bundled table, so it is as cacheable as a taken. Nothing in the server turns either of them into available.

There is no private= parameter, and the rule from Brand and reserved TLDs applies as it does to the CLI: tld=all, tld=rdap and tld=popular leave the closed zones out, and a TLD the caller names is checked whatever it is. So tld=aws is answered — private, with the operator attached — which is what --private include is for on the command line. What the API will not do is let one request spend hundreds of registry lookups sweeping zones the bundled table already has the answer for.

Running one

A reachable ds server is an open proxy onto other people’s registries: every request it accepts becomes a query made under your address, against a service that rate-limits hard. It therefore ships closed — loopback only, capped, paced and throttled — and the defaults are the interesting part:

Flag Default Meaning
--serve answer over HTTP instead of checking a name; required by all of the below
--host <ADDR> 127.0.0.1 bind address; anything else prints a warning
-p, --port <N> 8080 port
--max-lookups <N> 50 most domains one request may ask about (names × TLDs)
--rate-limit <N> 60 requests per minute per client address; 0 turns it off
--cache-ttl <SECS> 300 how long an answer is reused; 0 turns the cache off
-c, --concurrency <N> 20 lookups in flight across the whole server
--per-host <N> 4 parallel lookups against a single registry server
--timeout <SECS> 10 per-request timeout
--cors <ORIGIN> send Access-Control-Allow-Origin, so a browser page may call it
--source <auto|rdap|whois> auto as the CLI’s --source
--details --registry --where as the CLI’s flags of the same name
--no-iana never query whois.iana.org

Several of those are the CLI’s own flags rather than server copies of them: --concurrency, --per-host, --timeout, --source, --details, --registry, --where and --no-iana mean the same thing and default the same way whether or not --serve is on the line. The server-only options go the other way and are refused without it, so ds apple --port 9000 is an error rather than a port quietly thrown away.

The pacing described under Pacing is process-wide, not per request: one HostLimiter, so a hundred clients asking about .com queue behind the same per-host cap and share the same back-off. --max-lookups is what rules out tld=all — 50 leaves room for tld=popular.

The output flags default off, as they do on the command line. Raw WHOIS and raw RDAP have no query parameter at all: they are bulky, they are the registry’s text to publish rather than ours to mirror, and WHOIS records carry contact details the parsed --details fields leave out.

Behind a reverse proxy every client looks like the proxy, so --rate-limit becomes one budget for all of them — put the per-user limit in the proxy. X-Forwarded-For is deliberately not trusted: it is a header anyone can write, and honouring it would hand every client an unlimited supply of identities.


These pages are generated from the docs in the repo, so they never drift from what ships with the binary.