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
- Your first RDAP query with cURL
- A practical cURL command
- Format the response with jq
- Inspect the HTTP status and headers
- Make HTTP errors fail in a script
- Query domains, IP addresses and ASNs
- Find the authoritative base URL first
- Understand common RDAP errors
- Troubleshoot a cURL RDAP request
- A reusable shell example
- Frequently asked questions
- 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 sendAccept: 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.
| Option | Purpose |
|---|---|
--silent | Hides the progress meter so it does not interfere with JSON output. |
--show-error | Keeps cURL error messages visible when silent mode is active. |
--location | Follows HTTP redirects. |
--max-redirs 5 | Stops 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 10 | Limits the DNS, TCP and TLS connection phase to ten seconds. |
--max-time 30 | Limits the complete transfer to thirty seconds. |
--header | Requests the RDAP JSON media type. |
--user-agent | Identifies 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.
| Resource | Path pattern |
|---|---|
| Domain | domain/{fully-qualified-domain} |
| IP address or network | ip/{address-or-prefix} |
| Autonomous System Number | autnum/{number} |
| Nameserver | nameserver/{fully-qualified-hostname} |
| Entity | entity/{server-specific-handle} |
| Server help | help |
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.jsonfor domain namesipv4.jsonfor IPv4 addressesipv6.jsonfor IPv6 addressesasn.jsonfor 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 status | Typical interpretation |
|---|---|
200 OK | The server returned a response for the requested object. Validate the media type and JSON structure. |
301, 302, 303, 307 or 308 | Follow the supplied Location URL, with a redirect limit, HTTPS restriction and destination validation appropriate to the client. |
400 Bad Request | The query syntax or value could not be processed. Do not retry it unchanged. |
401 Unauthorized | The requested data requires authentication. |
403 Forbidden | Server policy prevents this client from accessing the resource. |
404 Not Found | The authoritative service has no matching object. This alone is not a complete domain-availability check. |
429 Too Many Requests | Reduce the request rate and honor Retry-After when present. |
5xx | The 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.