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.

GEThttps://dnsrobot.netBase URL/api/v2Version/whoisEndpoint?q=Parameters
200 OKRecorded 2026-10-25. Send it to run the request live.
{
  "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

  • qstringrequired
    A 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 written AS13335.

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.

  • queryobjectalways
    What was looked up, normalised (lower case, no trailing dot, IDNs as Punycode).
    • qstringalways
      What was looked up: the registrable domain (lower case, IDNs as Punycode), the IP address, or AS and the number.
  • kindstringalways
    What q is.

    one of "domain", "ip", "asn"

  • registeredbooleanalways
    The registry has a record. false for a domain that is free to register (or an address or AS number no registry holds); every registration field is then empty.
  • checkedAtstringalways
    When 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).
  • domainstringoptional
    Domain lookups: the registrable domain in ASCII (Punycode).
  • unicodeNamestring or nulloptional
    Domain lookups: the name in Unicode for an IDN (münchen.de), else null.
  • statestring or nulloptional
    Domain 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", null

  • registrarobject or nulloptional
    Domain lookups: the sponsoring registrar, null when the record names none.
    Show 4 fields
    • namestring or nullalways
      The registrar's name.
    • ianaIdstring or nullalways
      Its IANA registrar ID, only when the record says it is one.
    • urlstring or nullalways
      The registrar's own website (never an RDAP endpoint).
    • whoisServerstring or nullalways
      The registrar's WHOIS server, when the record names one.
  • datesobjectalways
    Registration dates (ISO 8601 UTC), null where the record has none.
    • createdstring or nullalways
      When it was first registered.
    • updatedstring or nullalways
      When the record last changed.
    • expiresstring or nullalways
      When the registration expires (domains only; null for IPs and AS numbers).
  • ageDaysinteger or nulloptional
    Domain lookups: whole days since registration.
  • expiresInDaysinteger or nulloptional
    Domain lookups: days until expiry, rounded up; negative once expired.
  • statusarray of stringsalways
    Status codes as the registry writes them: EPP codes for a domain (clientTransferProhibited, serverHold…), the RIR's for an IP network.
  • nameserversarray of stringsoptional
    Domain lookups: the delegated nameservers, lower case, no trailing dot.
  • dnssecboolean or nulloptional
    Domain lookups: the delegation is signed (DS records at the registry). null when the record doesn't say.
  • registrantobject or nulloptional
    Domain lookups: the registrant as the record publishes it; null when the domain isn't registered.
    • organizationstring or nullalways
      The registrant organization, when published.
    • countrystring or nullalways
      The registrant's country, when published (usually an ISO 3166-1 code).
  • redactedboolean or nulloptional
    Domain lookups: the registrant's details are withheld (GDPR or the registry's policy). null when the domain isn't registered.
  • registryIdstring or nulloptional
    Domain lookups: the registry's object id (ROID).
  • ipstringoptional
    IP lookups: the address, normalised (IPv6 compressed, lower case).
  • versionintegeroptional
    IP lookups: the IP version.

    one of 4, 6

  • networkobject or nulloptional
    IP lookups: the registered network (block) the address is in.
    Show 7 fields
    • namestring or nullalways
      The network's registered name (GOGL).
    • handlestring or nullalways
      The registry's handle for the network.
    • cidrstring or nullalways
      The block in CIDR notation, when the record gives one.
    • startstring or nullalways
      The block's first address.
    • endstring or nullalways
      The block's last address.
    • typestring or nullalways
      The allocation type as the RIR writes it (DIRECT ALLOCATION, ASSIGNED PA…).
    • parentHandlestring or nullalways
      The handle of the block it was carved from.
  • asnintegeroptional
    AS number lookups: the AS number.
  • namestring or nulloptional
    AS number lookups: the AS name as registered (CLOUDFLARENET).
  • handlestring or nulloptional
    AS number lookups: the registry's handle (AS13335).
  • organizationstring or nulloptional
    IP and AS number lookups: the organization that holds the network or AS number.
  • countrystring or nulloptional
    IP and AS number lookups: the registered country (ISO 3166-1 alpha-2): the holder's, not where servers stand.
  • rirstring or nulloptional
    IP and AS number lookups: the regional internet registry that answered.

    one of "ARIN", "RIPE NCC", "APNIC", "LACNIC", "AFRINIC", null

  • remarksarray of stringsoptional
    IP lookups: the record's remarks (at most six lines).
  • abuseobjectalways
    Where to report abuse: the registrar's abuse desk for a domain, the network's for an IP or AS number.
    • emailstring or nullalways
      Abuse email address.
    • phonestring or nullalways
      Abuse phone number.
  • sourceobject or nullalways
    Where the answer came from; null when the registry has no record.
    • protocolstringalways
      RDAP (JSON over HTTPS) or WHOIS (port 43 text).

      one of "rdap", "whois"

    • serversarray of stringsalways
      The servers asked, in order: the registry's, then the registrar's when its record was read.
  • issuesarray of objectsalways
    Problems found in the target's configuration, worst first. Empty when there are none.
    • severitystringalways
      error breaks something, warning risks it, info is worth knowing.

      one of "error", "warning", "info"

    • codestringalways
      Stable machine-readable code.
    • messagestringalways
      The problem and what to do about it, in plain English.

Errors

  • 422 target_not_allowed A 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.
  • 503 unavailable The registry didn't answer, answered with an error, or is rate-limiting lookups; retry after Retry-After seconds.

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
200 OKRecorded 2026-10-25
{
  "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
200 OKRecorded 2026-10-25
{
  "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
200 OKRecorded 2026-10-25
{
  "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
}