GET/api/v2/whois
WHOIS lookup API
Registration data for a domain, an IP address or an AS number, from its registry's RDAP server or WHOIS.
- 20 calls a minute per IP
- Same engine as the WHOIS Lookup tool
{
"query": {
"q": "google.com"
},
"kind": "domain",
"registered": true,
"checkedAt": "2026-10-25T08:12:59.191Z",
"domain": "google.com",
"unicodeName": null,
"state": "locked",
"registrar": {
"name": "MarkMonitor Inc.",
"ianaId": "292",
"url": "http://www.markmonitor.com",
"whoisServer": "whois.markmonitor.com"
},
"dates": {
"created": "1997-09-15T04:00:00.000Z",
"updated": "2019-09-09T15:39:04.000Z",
"expires": "2028-09-14T04:00:00.000Z"
},
"ageDays": 10632,
"expiresInDays": 690,
"status": [
"clientDeleteProhibited",
"clientTransferProhibited",
"clientUpdateProhibited",
"serverDeleteProhibited",
"serverTransferProhibited",
"serverUpdateProhibited"
],
"nameservers": [
"ns1.google.com",
"ns2.google.com",
"ns3.google.com",
"ns4.google.com"
],
"dnssec": false,
"registrant": {
"organization": null,
"country": "US"
},
"redacted": true,
"registryId": "2138514_DOMAIN_COM-VRSN",
"abuse": {
"email": "abusecomplaints@markmonitor.com",
"phone": "+1.2086851750"
},
"source": {
"protocol": "rdap",
"servers": [
"https://rdap.verisign.com/com/v1/",
"https://rdap.markmonitor.com/"
]
},
"issues": [],
"tookMs": 2023
}How it works
Asks the registry that holds the record. A domain comes from its registry's RDAP server (RFC 9083), filled from the registrar's own RDAP record (contacts, abuse desk, website), or over WHOIS port 43 for TLDs without RDAP (.jp, .ru, .it, .eu, .cn…). An IP address or AS number comes from its regional internet registry (ARIN, RIPE NCC, APNIC, LACNIC or AFRINIC), picked from IANA's bootstrap files.
A subdomain, URL or email address is reduced to its registrable domain with the Public Suffix List, so mail.google.com asks about google.com (query.q says what was asked) and is never reported as available. A name the registry has no record of is a finding: registered: false, a 200.
Dates are ISO 8601 UTC. status holds the EPP codes as the registry writes them (clientTransferProhibited…) and state sums them up with the expiry date; issues flags a domain that is expired, in redemption, pending deletion, on hold, without nameservers or expiring within 30 days. Registrant details are only what the record publishes: most gTLD records are redacted (GDPR), and redacted says so.
A TLD with no public WHOIS or RDAP (.es, .vn) or a registry that refuses our server is a 422; a registry that is down or rate-limiting lookups is a 503 with Retry-After.
Answers kept: A found record is kept an hour and a not-registered answer ten minutes, shared with the WHOIS Lookup page; `Cache-Control: max-age` says how long this answer has left.
Query parameters
qstringrequiredA domain name (a URL, email address or subdomain is fine: it is reduced to its registrable domain; IDNs in Unicode or Punycode), an IPv4 or IPv6 address, or an AS number writtenAS13335.
Response fields
200 with this JSON object, plus tookMs, and incomplete with warnings when a source failed. Fields marked optional appear only when they apply.
queryobjectalwaysWhat was looked up, normalised (lower case, no trailing dot, IDNs as Punycode).qstringalwaysWhat was looked up: the registrable domain (lower case, IDNs as Punycode), the IP address, orASand the number.
kindstringalwaysWhatqis.one of
"domain","ip","asn"registeredbooleanalwaysThe registry has a record.falsefor a domain that is free to register (or an address or AS number no registry holds); every registration field is then empty.checkedAtstringalwaysWhen the registry was asked (ISO 8601 UTC): a kept answer can be up to an hour old (ten minutes for a domain that isn't registered).domainstringoptionalDomain lookups: the registrable domain in ASCII (Punycode).unicodeNamestring or nulloptionalDomain lookups: the name in Unicode for an IDN (münchen.de), else null.statestring or nulloptionalDomain lookups: the domain's state from its status codes and expiry, most serious first. null when it isn't registered.one of
"pending_delete","redemption","expired","hold","inactive","expiring","locked","active",nullregistrarobject or nulloptionalDomain lookups: the sponsoring registrar, null when the record names none.Show 4 fields
namestring or nullalwaysThe registrar's name.ianaIdstring or nullalwaysIts IANA registrar ID, only when the record says it is one.urlstring or nullalwaysThe registrar's own website (never an RDAP endpoint).whoisServerstring or nullalwaysThe registrar's WHOIS server, when the record names one.
datesobjectalwaysRegistration dates (ISO 8601 UTC), null where the record has none.createdstring or nullalwaysWhen it was first registered.updatedstring or nullalwaysWhen the record last changed.expiresstring or nullalwaysWhen the registration expires (domains only; null for IPs and AS numbers).
ageDaysinteger or nulloptionalDomain lookups: whole days since registration.expiresInDaysinteger or nulloptionalDomain lookups: days until expiry, rounded up; negative once expired.statusarray of stringsalwaysStatus codes as the registry writes them: EPP codes for a domain (clientTransferProhibited,serverHold…), the RIR's for an IP network.nameserversarray of stringsoptionalDomain lookups: the delegated nameservers, lower case, no trailing dot.dnssecboolean or nulloptionalDomain lookups: the delegation is signed (DS records at the registry). null when the record doesn't say.registrantobject or nulloptionalDomain lookups: the registrant as the record publishes it; null when the domain isn't registered.organizationstring or nullalwaysThe registrant organization, when published.countrystring or nullalwaysThe registrant's country, when published (usually an ISO 3166-1 code).
redactedboolean or nulloptionalDomain lookups: the registrant's details are withheld (GDPR or the registry's policy). null when the domain isn't registered.registryIdstring or nulloptionalDomain lookups: the registry's object id (ROID).ipstringoptionalIP lookups: the address, normalised (IPv6 compressed, lower case).versionintegeroptionalIP lookups: the IP version.one of
4,6networkobject or nulloptionalIP lookups: the registered network (block) the address is in.Show 7 fields
namestring or nullalwaysThe network's registered name (GOGL).handlestring or nullalwaysThe registry's handle for the network.cidrstring or nullalwaysThe block in CIDR notation, when the record gives one.startstring or nullalwaysThe block's first address.endstring or nullalwaysThe block's last address.typestring or nullalwaysThe allocation type as the RIR writes it (DIRECT ALLOCATION,ASSIGNED PA…).parentHandlestring or nullalwaysThe handle of the block it was carved from.
asnintegeroptionalAS number lookups: the AS number.namestring or nulloptionalAS number lookups: the AS name as registered (CLOUDFLARENET).handlestring or nulloptionalAS number lookups: the registry's handle (AS13335).organizationstring or nulloptionalIP and AS number lookups: the organization that holds the network or AS number.countrystring or nulloptionalIP and AS number lookups: the registered country (ISO 3166-1 alpha-2): the holder's, not where servers stand.rirstring or nulloptionalIP and AS number lookups: the regional internet registry that answered.one of
"ARIN","RIPE NCC","APNIC","LACNIC","AFRINIC",nullremarksarray of stringsoptionalIP lookups: the record's remarks (at most six lines).abuseobjectalwaysWhere to report abuse: the registrar's abuse desk for a domain, the network's for an IP or AS number.emailstring or nullalwaysAbuse email address.phonestring or nullalwaysAbuse phone number.
sourceobject or nullalwaysWhere the answer came from; null when the registry has no record.protocolstringalwaysRDAP (JSON over HTTPS) or WHOIS (port 43 text).one of
"rdap","whois"serversarray of stringsalwaysThe servers asked, in order: the registry's, then the registrar's when its record was read.
issuesarray of objectsalwaysProblems found in the target's configuration, worst first. Empty when there are none.severitystringalwayserrorbreaks something,warningrisks it,infois worth knowing.one of
"error","warning","info"codestringalwaysStable machine-readable code.messagestringalwaysThe problem and what to do about it, in plain English.
Errors
422target_not_allowedA private or reserved IP address or AS number; a TLD with no public WHOIS or RDAP service (.es, .vn); a registry whose WHOIS refuses our server or answers in a layout we can't read.503unavailableThe registry didn't answer, answered with an error, or is rate-limiting lookups; retry afterRetry-Afterseconds.
Plus the errors every endpoint can return: 400 for a missing or unreadable parameter, 429 past the limit, 503 when every source failed.
Code samples
curl "https://dnsrobot.net/api/v2/whois?q=google.com"const params = new URLSearchParams({ q: "google.com" });
const res = await fetch(`https://dnsrobot.net/api/v2/whois?${params}`);
const data = await res.json();
if (!res.ok) throw new Error(data.error.message);
console.log(data.registrar);import requests
r = requests.get(
"https://dnsrobot.net/api/v2/whois",
params={"q": "google.com"},
timeout=30,
)
data = r.json()
if not r.ok:
raise RuntimeError(data["error"]["message"])
print(data["registrar"])package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
q := url.Values{"q": {"google.com"}}
res, err := http.Get("https://dnsrobot.net/api/v2/whois?" + q.Encode())
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]any
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
panic(err)
}
if res.StatusCode != http.StatusOK {
panic(data["error"])
}
fmt.Println(data["registrar"])
}<?php
$query = http_build_query(["q" => "google.com"]);
$context = stream_context_create(["http" => ["ignore_errors" => true, "timeout" => 30]]);
$data = json_decode(file_get_contents("https://dnsrobot.net/api/v2/whois?" . $query, false, $context), true);
if (isset($data["error"])) {
throw new RuntimeException($data["error"]["message"]);
}
print_r($data["registrar"]);require "net/http"
require "json"
uri = URI("https://dnsrobot.net/api/v2/whois")
uri.query = URI.encode_www_form(q: "google.com")
data = JSON.parse(Net::HTTP.get(uri))
raise data["error"]["message"] if data["error"]
puts data["registrar"]// Cargo.toml: reqwest = { version = "0.13", features = ["blocking", "json"] }, serde_json = "1"
fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = reqwest::blocking::get("https://dnsrobot.net/api/v2/whois?q=google.com")?;
let ok = res.status().is_success();
let data: serde_json::Value = res.json()?;
if !ok {
return Err(data["error"]["message"].to_string().into());
}
println!("{}", data["registrar"]);
Ok(())
}using System.Text.Json;
using var http = new HttpClient();
var res = await http.GetAsync("https://dnsrobot.net/api/v2/whois?q=google.com");
var data = JsonDocument.Parse(await res.Content.ReadAsStringAsync()).RootElement;
if (!res.IsSuccessStatusCode)
throw new Exception(data.GetProperty("error").GetProperty("message").GetString());
Console.WriteLine(data.GetProperty("registrar"));A domain (google.com)
GET /api/v2/whois?q=google.com{
"query": {
"q": "google.com"
},
"kind": "domain",
"registered": true,
"checkedAt": "2026-10-25T08:12:59.191Z",
"domain": "google.com",
"unicodeName": null,
"state": "locked",
"registrar": {
"name": "MarkMonitor Inc.",
"ianaId": "292",
"url": "http://www.markmonitor.com",
"whoisServer": "whois.markmonitor.com"
},
"dates": {
"created": "1997-09-15T04:00:00.000Z",
"updated": "2019-09-09T15:39:04.000Z",
"expires": "2028-09-14T04:00:00.000Z"
},
"ageDays": 10632,
"expiresInDays": 690,
"status": [
"clientDeleteProhibited",
"clientTransferProhibited",
"clientUpdateProhibited",
// … 3 more items
],
"nameservers": [
"ns1.google.com",
"ns2.google.com",
"ns3.google.com",
// … 1 more item
],
"dnssec": false,
"registrant": {
"organization": null,
"country": "US"
},
"redacted": true,
"registryId": "2138514_DOMAIN_COM-VRSN",
"abuse": {
"email": "abusecomplaints@markmonitor.com",
"phone": "+1.2086851750"
},
"source": {
"protocol": "rdap",
"servers": [
"https://rdap.verisign.com/com/v1/",
"https://rdap.markmonitor.com/"
]
},
"issues": [],
"tookMs": 2023
}Shortened for the page: long lists show their first items.
An IP address (1.1.1.1)
GET /api/v2/whois?q=1.1.1.1{
"query": {
"q": "1.1.1.1"
},
"kind": "ip",
"registered": true,
"checkedAt": "2026-10-25T08:15:00.192Z",
"ip": "1.1.1.1",
"version": 4,
"network": {
"name": "APNIC-LABS",
"handle": "1.1.1.0 - 1.1.1.255",
"cidr": "1.1.1.0/24",
"start": "1.1.1.0",
"end": "1.1.1.255",
"type": "ASSIGNED PORTABLE",
"parentHandle": null
},
"organization": "APNIC Research and Development",
"country": "AU",
"rir": "APNIC",
"dates": {
"created": "2011-08-10T23:12:35.000Z",
"updated": "2023-04-26T22:57:58.000Z",
"expires": null
},
"status": [
"active"
],
"remarks": [
"APNIC and Cloudflare DNS Resolver project",
"Routed globally by AS13335/Cloudflare",
"Research prefix for APNIC Labs",
// … 3 more items
],
"abuse": {
"email": "helpdesk@apnic.net",
"phone": null
},
"source": {
"protocol": "rdap",
"servers": [
"https://rdap.apnic.net/"
]
},
"issues": [],
"tookMs": 0
}Shortened for the page: long lists show their first items.
An AS number (AS13335)
GET /api/v2/whois?q=AS13335{
"query": {
"q": "AS13335"
},
"kind": "asn",
"registered": true,
"checkedAt": "2026-10-25T08:13:01.626Z",
"asn": 13335,
"name": "CLOUDFLARENET",
"handle": "AS13335",
"organization": "Cloudflare, Inc.",
"country": null,
"rir": "ARIN",
"dates": {
"created": "2010-07-14T22:35:57.000Z",
"updated": "2017-02-17T23:04:32.000Z",
"expires": null
},
"status": [],
"abuse": {
"email": "abuse@cloudflare.com",
"phone": null
},
"source": {
"protocol": "rdap",
"servers": [
"https://rdap.arin.net/"
]
},
"issues": [],
"tookMs": 452
}