Get parsed WHOIS records, normalized RDAP data, DNS records, and TLS certificate details for any domain, all as clean JSON over HTTPS. Because we keep the history, you can also see what changed and when, from a domain moving to a new registrar to a swapped set of nameservers or a fresh certificate. Zone feeds let you watch a whole TLD day by day and catch new registrations, nameserver moves, and drops as they happen. Start free with no card, and build anything from a quick lookup tool to a brand monitor to a research pipeline over millions of domains.
Create a key on the API keys page. Keys are shown once at creation — store yours securely. Send the key with every request as a Bearer token in the Authorization header: Authorization: Bearer wis_live_<key>. Never put the key in a query string. A missing or invalid key returns 401 unauthorized.
The API is also available to AI clients over the Model Context Protocol. Point your client at https://api.who.is/v1/mcp and authenticate with the same API key, sent as an Authorization: Bearer header.
Tools: whois, rdap, dns, dns_changes, certificates, certificates_changes, domain_history, domain_history_snapshots, nameservers, nameserver, nameserver_domains, what_changed. Each tool spends the same credits as the endpoint it calls; the full history tool spends 200 credits once per domain and its retries are free.
Credits & plans
Every API call costs credits: 1 for a lookup, change timeline, or zone-feed page; 2 for a live refresh; 200 for a full-history query. Not-found responses are free. Your plan grants a fresh allowance of credits each calendar month (UTC). Credits you buy ($4.99 per 2,000, any quantity) never expire and are used after your allowance. The free allowance covers cached lookups only; paid endpoints use a paid plan's allowance or purchased credits.
What a call costs
Call
Credits
Lookup (WHOIS, RDAP, DNS, certificate, history summary, nameserver)
1
DNS or certificate change timeline
1
Live upstream refresh (?live=true)
2
Zone-event feed page
1
Full domain history (per domain, per archive generation)
200
Plans
Plan
Price
Credits / month
Requests / second
Live refreshes / day
Paid endpoints
Free
$0
500
1
0
No
Pro API Access
$29.00/mo
15,000
5
1,000
Yes
Growth API Access
$99.00/mo
60,000
5
2,000
Yes
Scale API Access
$199.00/mo
150,000
5
4,000
Yes
Credit packs: $4.99 per 2,000 credits — buy any quantity from your API keys page. DNS and certificate change timelines (/changes) are paid endpoints — current-state DNS and certificate lookups are on every plan; on Free without purchased credits the timelines return 403 plan_required.
Endpoints
GET/v1/whois/{domain}
Snapshot-first parsed WHOIS: registrar, statuses, events, nameservers, and redacted-as-received contacts. Serves a stored snapshot (≤30 days) unless `?live=true` forces an upstream refresh. Raw upstream text is never returned.
Parameters
Name
In
Required
Description
domain
path
yes
The domain to look up, e.g. `example.com`. A subdomain is resolved to its registrable domain (`www.example.com` → `example.com`).
live
query
no
Set to `true` to force a fresh upstream lookup (bounded by a 1-hour floor). A paid endpoint costing 2 credits — the free allowance cannot pay for it, so a free key with no purchased credits is denied with `plan_required`. A daily live refresh limit also applies. Any other value is a normal snapshot lookup.
Snapshot-first normalized RDAP: entities (recursing through sub-entities), events, and nameservers. Serves a stored snapshot unless `?live=true` forces an upstream refresh. Never an upstream passthrough.
Parameters
Name
In
Required
Description
domain
path
yes
The domain to look up, e.g. `example.com`. A subdomain is resolved to its registrable domain (`www.example.com` → `example.com`).
live
query
no
Set to `true` to force a fresh upstream lookup (bounded by a 1-hour floor). A paid endpoint costing 2 credits — the free allowance cannot pay for it, so a free key with no purchased credits is denied with `plan_required`. A daily live refresh limit also applies. Any other value is a normal snapshot lookup.
A domain's history at a glance: snapshot, change, and registrar counts plus the first/last-seen window, drawn from our archive of 2B+ WHOIS/RDAP snapshots going back to 2003. Available on every plan; the full per-snapshot history is a separate endpoint.
Parameters
Name
In
Required
Description
domain
path
yes
The domain to look up, e.g. `example.com`. A subdomain is resolved to its registrable domain (`www.example.com` → `example.com`).
The complete per-snapshot history from the 2B+ snapshot archive: every parsed WHOIS/RDAP snapshot (facts only — never raw text) plus the field-diff change timeline. A paid endpoint: a free key with no purchased credits is denied with `plan_required`.
This endpoint is **async-or-cached** and does not run the archive query on the request path. A prepared result is served immediately (`200`); otherwise the call returns `202 { "status": "preparing", "retry_after": 10 }` with a `Retry-After` header — poll until it returns `200`. If preparation failed, `502 upstream_unavailable` is returned and the next call re-queues.
**Charge-once:** this endpoint spends 200 credits once per domain per archive generation — the first request that enqueues (or serves) a given domain's history pays it; subsequent polls and re-reads of the same domain (within the same archive generation) spend the ordinary 1-credit lookup instead.
**Errors are never charged:** a `503` (queue/metering unavailable) refunds the request, and a failed preparation (`502`) additionally refunds the 200 credits you paid — retrying after a `502` starts (and charges) fresh.
Parameters
Name
In
Required
Description
domain
path
yes
The domain to look up, e.g. `example.com`. A subdomain is resolved to its registrable domain (`www.example.com` → `example.com`).
The zone's current records with hosting classification. Observation begins at first interest — a first query for an unobserved domain resolves it live, records the observation, and serves it; a domain with no DNS records returns `not_found`.
Parameters
Name
In
Required
Description
domain
path
yes
The domain to look up, e.g. `example.com`. A subdomain is resolved to its registrable domain (`www.example.com` → `example.com`).
Every recorded change to this zone's DNS records, oldest first. Entries are changes only — a record set that stayed the same does not produce one — and each entry carries what changed, when it took effect, and how long it stood. An empty timeline is a valid 200 with an empty `changes` array. `snapshot_time` describes the whole timeline we hold for the zone, not just the page in hand. Requires a paid plan: on the Free plan this endpoint returns `plan_required` (403).
Pass `pagination.next_cursor` back unchanged to fetch the next page; `next_cursor: null` means you have reached the last page. Entries are only ever appended, so you can keep the last cursor and re-use it later to pick up whatever has since been observed.
Parameters
Name
In
Required
Description
domain
path
yes
The domain to look up, e.g. `example.com`. A subdomain is resolved to its registrable domain (`www.example.com` → `example.com`).
limit
query
no
Results per page (1–1000, default 100). A value above 1000 is clamped to 1000.
cursor
query
no
Opaque cursor from a prior response's `pagination.next_cursor`. Pass it back unchanged, with the same path and query parameters, to fetch the next page. A cursor used with a different query returns 400 `invalid_cursor`.
The current leaf certificate for a host: issuer, subject, SANs, validity window, and structural chain status. Serves the stored certificate; a first query for an unobserved host probes it live (at most once per 24h), records the observation, and serves it. Certificates are host-specific, so a subdomain is looked up as-is.
Parameters
Name
In
Required
Description
domain
path
yes
The host to look up, e.g. `example.com` or `shop.example.com`. Certificates are host-specific, so a subdomain is looked up as-is.
Every certificate this host has been observed serving, oldest first — one entry per certificate, with what changed at each rotation and the window it was served in. An empty timeline is a valid 200 with an empty `changes` array. `snapshot_time` describes the whole timeline we hold for the host, not just the page in hand. Requires a paid plan: on the Free plan this endpoint returns `plan_required` (403).
Pass `pagination.next_cursor` back unchanged to fetch the next page; `next_cursor: null` means you have reached the last page. Entries are only ever appended, so you can keep the last cursor and re-use it later to pick up whatever has since been observed.
Parameters
Name
In
Required
Description
domain
path
yes
The host to look up, e.g. `example.com` or `shop.example.com`. Certificates are host-specific, so a subdomain is looked up as-is.
limit
query
no
Results per page (1–1000, default 100). A value above 1000 is clamped to 1000.
cursor
query
no
Opaque cursor from a prior response's `pagination.next_cursor`. Pass it back unchanged, with the same path and query parameters, to fetch the next page. A cursor used with a different query returns 400 `invalid_cursor`.
The domains that appeared in a TLD zone on a given day, with their nameservers. Use it to watch for newly registered domains — for example, to catch look-alikes of your brand as soon as they show up. Returns one day per call (default: the most recent available day); page through the results with the cursor, and filter by `tld` or by a substring of the domain name.
Pass `pagination.next_cursor` back unchanged (with the same `date` and filters) to fetch the next page; `next_cursor: null` means you have reached the last page. Requires a paid plan.
Parameters
Name
In
Required
Description
date
query
no
The day to fetch (YYYY-MM-DD, UTC). Defaults to the most recent available day. A day with no data returns 404.
tld
query
no
Restrict to these TLDs (repeatable or comma-separated), lowercased, no leading dot. Max 50. Omit for all TLDs.
limit
query
no
Results per page (1–1000, default 100). A value above 1000 is clamped to 1000.
cursor
query
no
Opaque cursor from a prior response's `pagination.next_cursor`. Pass it back unchanged, with the same path and query parameters, to fetch the next page. A cursor used with a different query returns 400 `invalid_cursor`.
contains
query
no
Only return domains whose name contains these substrings. Repeatable, up to 5 terms, each at least 3 characters; a domain must contain all of them.
The domains whose nameservers changed in a TLD zone on a given day, with both the previous and the new nameservers. Use it to spot registrar or hosting migrations — for example, to detect when a domain you track moves to a different provider. Returns one day per call (default: the most recent available day); page through the results with the cursor, and filter by `tld` or by a substring of the domain name.
Pass `pagination.next_cursor` back unchanged (with the same `date` and filters) to fetch the next page; `next_cursor: null` means you have reached the last page. Requires a paid plan.
Parameters
Name
In
Required
Description
date
query
no
The day to fetch (YYYY-MM-DD, UTC). Defaults to the most recent available day. A day with no data returns 404.
tld
query
no
Restrict to these TLDs (repeatable or comma-separated), lowercased, no leading dot. Max 50. Omit for all TLDs.
limit
query
no
Results per page (1–1000, default 100). A value above 1000 is clamped to 1000.
cursor
query
no
Opaque cursor from a prior response's `pagination.next_cursor`. Pass it back unchanged, with the same path and query parameters, to fetch the next page. A cursor used with a different query returns 400 `invalid_cursor`.
contains
query
no
Only return domains whose name contains these substrings. Repeatable, up to 5 terms, each at least 3 characters; a domain must contain all of them.
The domains that were removed from a TLD zone on a given day. Use it to find dropped or expired domains — for example, to track when a name you want becomes available. Returns one day per call (default: the most recent available day); page through the results with the cursor, and filter by `tld` or by a substring of the domain name.
Pass `pagination.next_cursor` back unchanged (with the same `date` and filters) to fetch the next page; `next_cursor: null` means you have reached the last page. Requires a paid plan.
Parameters
Name
In
Required
Description
date
query
no
The day to fetch (YYYY-MM-DD, UTC). Defaults to the most recent available day. A day with no data returns 404.
tld
query
no
Restrict to these TLDs (repeatable or comma-separated), lowercased, no leading dot. Max 50. Omit for all TLDs.
limit
query
no
Results per page (1–1000, default 100). A value above 1000 is clamped to 1000.
cursor
query
no
Opaque cursor from a prior response's `pagination.next_cursor`. Pass it back unchanged, with the same path and query parameters, to fetch the next page. A cursor used with a different query returns 400 `invalid_cursor`.
contains
query
no
Only return domains whose name contains these substrings. Repeatable, up to 5 terms, each at least 3 characters; a domain must contain all of them.
The nameserver hosts at or under a name, busiest first — for example, `under=example-dns.com` lists `example-dns.com` itself and every `*.example-dns.com` host a provider runs, each with the number of domains currently delegated to it. Use it to find the exact host names to pass to the per-host endpoints, or to size a provider at a glance. `under` is required and must be a domain name, not a bare TLD.
Pass `pagination.next_cursor` back unchanged (with the same `under`) to fetch the next page; `next_cursor: null` means you have reached the last page.
Parameters
Name
In
Required
Description
under
query
yes
The scope to list nameservers under, e.g. `example-dns.com` returns `ns1.example-dns.com`, `ns2.example-dns.com`, …. Matches the name itself and every subdomain of it, so a full host such as `ns1.example-dns.com` lists that host. Must be a domain name such as `example-dns.com`, not a bare TLD such as `com`.
limit
query
no
Results per page (1–1000, default 100). A value above 1000 is clamped to 1000.
cursor
query
no
Opaque cursor from a prior response's `pagination.next_cursor`. Pass it back unchanged, with the same path and query parameters, to fetch the next page. A cursor used with a different query returns 400 `invalid_cursor`.
How many domains are currently delegated to a nameserver host in the zone census, and when that count last changed. A host we have never seen returns `not_found`.
Parameters
Name
In
Required
Description
host
path
yes
The nameserver host name, e.g. `ns1.example-dns.com`. Case-insensitive; a trailing dot is ignored.
The domains currently delegated to a nameserver host, in byte order of the domain name. Use it to enumerate a provider's or a competitor's customer base, or to audit every domain pointed at your own nameservers. `added_at` is the zone day we first recorded the delegation, or null for delegations that predate tracking. A known host with no delegations returns an empty `data`; a host we have never seen returns `not_found`.
Pass `pagination.next_cursor` back unchanged to fetch the next page; `next_cursor: null` means you have reached the last page. The listing is not filterable by name — page through it, or start from the zone feeds for day-by-day changes.
Parameters
Name
In
Required
Description
host
path
yes
The nameserver host name, e.g. `ns1.example-dns.com`. Case-insensitive; a trailing dot is ignored.
limit
query
no
Results per page (1–1000, default 100). A value above 1000 is clamped to 1000.
cursor
query
no
Opaque cursor from a prior response's `pagination.next_cursor`. Pass it back unchanged, with the same path and query parameters, to fetch the next page. A cursor used with a different query returns 400 `invalid_cursor`.
Every response carries X-RateLimit-Limit and X-RateLimit-Remaining, which describe the credit bucket that funded the call — your monthly allowance, or your purchased credits when the allowance is spent. Every metered success also carries X-Credits-Charged (the credits the call cost; 0 on a not-found, which is refunded). A 429 additionally carries Retry-After (seconds to wait) — one second for a per-second rate limit, seconds-until-midnight for the daily live refresh limit, or seconds-until-the-1st for spent credits.
Error codes
Errors are application/problem+json (RFC 7807): { "type", "title", "status", "detail" }. The type is the stable machine-readable code.
type
HTTP
Meaning
invalid_domain
400
The domain could not be parsed.
invalid_request
400
A query parameter (date, tld, limit, or contains) was malformed.
invalid_cursor
400
The pagination cursor is malformed or does not belong to this query.
unauthorized
401
Missing, malformed, invalid, or revoked API key.
plan_required
403
A paid endpoint (live=true, a change timeline, a zone feed, full history) on a free plan with no purchased credits.
not_found
404
No record/observation exists for this domain yet.
domain_not_available
404
No record is available for this domain.
method_not_allowed
405
The HTTP method is not the one the endpoint serves.
payload_too_large
413
The request body is larger than the endpoint accepts.
rate_limited
429
Too many requests per second for your plan. Retry shortly.
quota_exceeded
429
Your credits are spent (or the daily live refresh limit is reached). See Retry-After.
upstream_unavailable
502
The upstream WHOIS/RDAP lookup could not be completed.
service_unavailable
503
The API is temporarily unable to meter the request. Retry shortly.
A note on DNS & certificate coverage
Our DNS and certificate observations grow from interest: the record for a domain begins the first time someone looks it up — a first query for an unobserved domain is answered live and recorded, so current-state lookups always work. Change timelines build from that point on, and an early query for a rarely-seen domain may return a short (or empty) one. Coverage compounds from usage, including your own.
Changelog
v1.0 — Launch: WHOIS, RDAP, domain history summary, and DNS & certificate current/changes endpoints.
v1.1 — MCP server at /v1/mcp, exposing the lookup, history, change-timeline and nameserver endpoints as tools.