How to Query an RDAP Server with cURL

Use cURL to send an RDAP request, inspect the HTTP response and work with the returned JSON from a terminal or shell script.

On this page
  1. Your first RDAP query with cURL
  2. A practical cURL command
  3. Format the response with jq
  4. Inspect the HTTP status and headers
  5. Make HTTP errors fail in a script
  6. Query domains, IP addresses and ASNs
  7. Find the authoritative base URL first
  8. Understand common RDAP errors
  9. Troubleshoot a cURL RDAP request
  10. A reusable shell example
  11. Frequently asked questions
  12. Primary references

RDAP is an HTTP-based protocol, so you do not need a specialized client to inspect a registration record. If you know the authoritative RDAP URL, a normal cURL GET request can retrieve the response as JSON.

This guide starts with a working domain query and then adds the options needed for redirects, errors, timeouts and shell scripts. It also shows the corresponding query paths for IP addresses, Autonomous System Numbers, nameservers and entities.

Quick answer: Run curl 'https://rdap.verisign.com/com/v1/domain/example.com' to retrieve a domain RDAP response. For routine use, also send Accept: application/rdap+json, follow a limited number of HTTPS redirects and inspect the HTTP status instead of assuming every response is a successful lookup.

Your first RDAP query with cURL

The following command requests the registration record for example.com from the RDAP service currently published for .com:

curl 'https://rdap.verisign.com/com/v1/domain/example.com'

cURL uses GET by default and writes the response body to standard output. A successful RDAP response is a JSON object that normally contains members such as rdapConformance and objectClassName.

The endpoint is not guessed from the domain name. It is the base URL published for .com, followed by the standardized path domain/example.com. RDAP is distributed across many operators, so another top-level domain can require a different base URL. Read how to find the RDAP server for a domain before substituting an arbitrary domain in this command.

A practical cURL command

For an interactive lookup, use a command that declares the expected media type, follows redirects and places limits on the request:

curl --silent --show-error \
  --location \
  --max-redirs 5 \
  --proto '=https' \
  --proto-redir '=https' \
  --connect-timeout 10 \
  --max-time 30 \
  --header 'Accept: application/rdap+json' \
  --user-agent 'ExampleRDAPClient/1.0 (contact@example.test)' \
  'https://rdap.verisign.com/com/v1/domain/example.com'

Replace the example user agent and contact address with values that identify your own client. A useful user agent can help an operator distinguish your legitimate requests from anonymous automated traffic and contact you if the client causes a problem.

OptionPurpose
--silentHides the progress meter so it does not interfere with JSON output.
--show-errorKeeps cURL error messages visible when silent mode is active.
--locationFollows HTTP redirects.
--max-redirs 5Stops a redirect loop after five redirects.
--proto '=https'Allows HTTPS for the initial request.
--proto-redir '=https'Refuses redirects to a non-HTTPS protocol.
--connect-timeout 10Limits the DNS, TCP and TLS connection phase to ten seconds.
--max-time 30Limits the complete transfer to thirty seconds.
--headerRequests the RDAP JSON media type.
--user-agentIdentifies the client making the request.

The leading = in the protocol options replaces cURL’s allowed protocol list instead of adding to it. These restrictions are useful when a script follows URLs supplied by a remote service.

HTTPS does not make every redirect destination trustworthy. A backend that accepts untrusted query URLs should validate each destination and block loopback, link-local, private-network and internal service addresses before following redirects. Protocol restrictions alone do not prevent server-side request forgery.

Format the response with jq

RDAP servers are not required to add whitespace or line breaks to their JSON. Pipe the response to jq when you want readable terminal output:

curl --silent --show-error \
  --location \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/domain/example.com' \
  | jq .

jq is optional and is not part of cURL. Without it, the server returns the same data, usually in a more compact form.

You can also select a small set of fields:

curl --silent --show-error \
  --location \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/domain/example.com' \
  | jq '{objectClassName, handle, ldhName, status}'

To list the events in a domain response:

curl --silent --show-error \
  --location \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/domain/example.com' \
  | jq '.events[]? | {action: .eventAction, date: .eventDate}'

The ? prevents jq from producing an error if the optional events array is absent. It does not mean that every returned date has the same meaning. Select events by eventAction, and consult the guide to reading an RDAP response before using these values in application logic.

Inspect the HTTP status and headers

RDAP uses HTTP status codes as part of the protocol. A JSON body alone does not tell you whether the requested object was found.

Use --include to display the response headers above the body:

curl --include \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/domain/example.com'

This is useful for manual debugging, but the combined headers and body are not valid JSON and should not be piped directly to jq.

To inspect only the headers while discarding the response body:

curl --silent --show-error \
  --dump-header - \
  --output /dev/null \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/domain/example.com'

On Windows, use --output NUL instead of --output /dev/null.

For a script, save the body and print only the numeric status to standard output:

if status=$(curl --silent --show-error \
  --location \
  --output response.json \
  --write-out '%{http_code}' \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/domain/example.com'); then
  printf 'HTTP status: %s\n' "$status"
else
  curl_exit=$?
  printf 'cURL failed with exit code %s\n' "$curl_exit" >&2
  exit "$curl_exit"
fi

cURL normally returns exit code zero when an HTTP transfer completes, even if the server returns 404 or 500. The HTTP status and the cURL process exit code answer different questions:

  • The HTTP status describes the RDAP server’s response.
  • The cURL exit code describes whether cURL completed the requested transfer.

Make HTTP errors fail in a script

When a shell script should fail on an HTTP error, add --fail-with-body:

curl --silent --show-error \
  --fail-with-body \
  --location \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/domain/not-registered.example.com'

The example asks the .com service about a subdomain of the reserved example.com domain. It stays within the server’s authoritative namespace but is not a separately registered .com object, so the service returns an RDAP 404 error.

For an HTTP status of 400 or greater, --fail-with-body preserves the response body and makes cURL exit with code 22. Preserving the body matters because a conforming RDAP error response can contain a useful JSON errorCode, title, description and links.

--fail-with-body was added in cURL 7.76.0. Older versions support --fail, but that option suppresses the HTTP error body. Check the installed version with curl --version before depending on newer options in a portable script.

If you pipe cURL into jq in Bash or another shell that supports pipefail, enable pipeline failure handling so a cURL failure is not hidden by a successful jq process:

set -o pipefail

curl --silent --show-error \
  --fail-with-body \
  --location \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/domain/example.com' \
  | jq .

Query domains, IP addresses and ASNs

RDAP exact-match requests use a resource-specific path after the server’s base URL.

ResourcePath pattern
Domaindomain/{fully-qualified-domain}
IP address or networkip/{address-or-prefix}
Autonomous System Numberautnum/{number}
Nameservernameserver/{fully-qualified-hostname}
Entityentity/{server-specific-handle}
Server helphelp

The server base URL depends on the resource. A domain registry is not necessarily authoritative for an IP address or ASN.

Query a domain

curl --silent --show-error \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/domain/example.com' \
  | jq .

Use a complete domain name. For an internationalized domain, consistently use either the Unicode U-label form or the ASCII A-label form; the A-label form is usually more predictable in shell scripts. Do not mix the two forms in one name.

Query an IP address

curl --silent --show-error \
  --header 'Accept: application/rdap+json' \
  'https://rdap.arin.net/registry/ip/8.8.8.8' \
  | jq .

The result describes the most specific registered network containing the address. It is not a geolocation result and does not necessarily identify the individual user of that address.

After retrieving the JSON, use the guide to reading an IP address RDAP response to interpret the returned range, CIDR prefixes, allocation hierarchy and abuse contacts.

An RDAP IP query can also contain a CIDR prefix. Keep the complete URL quoted so shell metacharacters cannot alter it:

curl --silent --show-error \
  --header 'Accept: application/rdap+json' \
  'https://rdap.arin.net/registry/ip/8.8.8.0/24' \
  | jq .

Query an Autonomous System Number

curl --silent --show-error \
  --header 'Accept: application/rdap+json' \
  'https://rdap.arin.net/registry/autnum/15169' \
  | jq .

The autnum path takes the numeric asplain value, so use 15169, not AS15169.

After retrieving the JSON, use the guide to reading an ASN RDAP response to interpret the returned range, registration status, entities and contacts without confusing registration data with live routing evidence.

Query a nameserver or entity

Nameserver and entity lookups use the service that knows about the associated object:

curl --silent --show-error \
  --header 'Accept: application/rdap+json' \
  'https://rdap.example.test/nameserver/ns1.example.test'
curl --silent --show-error \
  --header 'Accept: application/rdap+json' \
  'https://rdap.example.test/entity/ENTITY-HANDLE'

These URLs are structural examples, not live services. Entity handles are specific to a registration provider, and the IANA bootstrap registries do not provide a universal route for arbitrary entity or help queries.

Request server help

An RDAP server can publish terms of service, rate-limit policy, supported extensions and contact information through its help endpoint:

curl --silent --show-error \
  --header 'Accept: application/rdap+json' \
  'https://rdap.verisign.com/com/v1/help' \
  | jq .

The amount of help information varies by operator.

Find the authoritative base URL first

cURL transfers a URL; it does not perform RDAP bootstrap discovery automatically. Before constructing a query, obtain the base URL from the relevant IANA RDAP bootstrap registry:

  • dns.json for domain names
  • ipv4.json for IPv4 addresses
  • ipv6.json for IPv6 addresses
  • asn.json for Autonomous System Numbers

For example, this command displays the HTTPS base URLs currently associated with the com entry in IANA’s DNS bootstrap file:

curl --silent --show-error 'https://data.iana.org/rdap/dns.json' \
  | jq --raw-output \
      '.services[] | select(.[0][] == "com") | .[1][] | select(startswith("https://"))'

This one-off inspection is useful at a terminal, but it is not a complete production discovery implementation. A reusable client also needs to normalize input, handle internationalized labels, preserve base paths, choose among multiple URLs, cache bootstrap data and refresh it safely. The RDAP server discovery guide covers that process in detail.

You can also use the RDAP lookup tool when you want the site to discover the service and render the returned data for you.

Understand common RDAP errors

Do not interpret every non-200 result as an available domain or a broken server.

HTTP statusTypical interpretation
200 OKThe server returned a response for the requested object. Validate the media type and JSON structure.
301, 302, 303, 307 or 308Follow the supplied Location URL, with a redirect limit, HTTPS restriction and destination validation appropriate to the client.
400 Bad RequestThe query syntax or value could not be processed. Do not retry it unchanged.
401 UnauthorizedThe requested data requires authentication.
403 ForbiddenServer policy prevents this client from accessing the resource.
404 Not FoundThe authoritative service has no matching object. This alone is not a complete domain-availability check.
429 Too Many RequestsReduce the request rate and honor Retry-After when present.
5xxThe service has a server-side or temporary availability problem.

Use --retry cautiously. Retrying malformed requests or rate-limited requests without delay creates more traffic without fixing the cause. If you automate retries, keep them bounded, apply them only to temporary failures and follow the operator’s Retry-After instructions.

Troubleshoot a cURL RDAP request

The output is HTML instead of JSON

Check the HTTP status and Content-Type header. You may have queried a website homepage, omitted part of the published base path or been intercepted by a proxy. A successful RDAP response normally uses application/rdap+json; an HTML page is not an RDAP result merely because it came from the expected hostname.

The server returns 404

Confirm both parts of the URL: the authoritative base URL and the resource-specific query path. A correct authoritative server can also return 404 when no matching registration object exists.

The server returns 429

Stop sending requests at the current rate. Inspect the response headers and body for Retry-After or operator guidance, then reduce concurrency and add per-service rate limiting. Different RDAP operators can enforce different limits.

cURL reports a certificate error

Verify the hostname, system clock, cURL version and local certificate-authority store. Do not solve a production TLS failure with --insecure or -k; those options disable certificate verification and make it possible for an attacker to impersonate the RDAP service.

The command works without jq but fails with jq

Inspect the unformatted response and its content type. jq expects valid JSON, so it will reject HTML, an empty body or headers combined with the response through --include. It can also expose a truncated response caused by a network failure.

A reusable shell example

The following function queries a known HTTPS RDAP base URL, preserves its path, applies request limits and formats the JSON response:

rdap_get() {
  base_url=$1
  query_path=$2

  curl --silent --show-error \
    --fail-with-body \
    --location \
    --max-redirs 5 \
    --proto '=https' \
    --proto-redir '=https' \
    --connect-timeout 10 \
    --max-time 30 \
    --header 'Accept: application/rdap+json' \
    --user-agent 'ExampleRDAPClient/1.0 (contact@example.test)' \
    "${base_url}${query_path}"
}

set -o pipefail
rdap_get 'https://rdap.verisign.com/com/v1/' 'domain/example.com' | jq .

Pass a base URL ending in / and a query path without a leading /. This preserves operator-defined prefixes such as /com/v1/ rather than replacing them with a guessed /rdap/ path.

For untrusted input, do not concatenate raw strings without validation and encoding. Normalize the resource according to its RDAP query type, reject characters that do not belong in that type and use a URL library when implementing a general-purpose client. Server-side clients must also validate redirect destinations rather than assuming every HTTPS URL is safe to request.

Frequently asked questions

Does cURL automatically find the correct RDAP server?

No. cURL sends a request to the URL you provide. Domain, IP and ASN clients normally discover the authoritative base URL through the corresponding IANA bootstrap registry before constructing the final request.

Do I need to send an Accept header?

A basic request may work without one, but an RDAP client should explicitly request application/rdap+json. The response media type is also an important validation signal.

Should I use cURL’s --json option?

No. --json is intended for sending a JSON request body and implies headers used for an upload. A normal RDAP lookup is a GET request without a request body. Use --header 'Accept: application/rdap+json' instead.

Can a 404 prove that a domain is available to register?

No. It can show that a correctly selected authoritative RDAP service found no matching object, but registry reservations, eligibility rules, premium-name policy and other registration systems can still affect availability.

Can I use these commands in production?

They are a starting point, not a complete client. Production software should cache bootstrap registries, validate identifiers and responses, enforce redirect and timeout limits, respect rate limits, retain provenance and avoid assuming optional fields are always present.

Primary references

Back to top