Python SDK for the RDAP API — look up domains, IPs, ASNs, nameservers, and entities.
Project description
RDAP API Python SDK
Official Python SDK for the RDAP API — look up domains, IP addresses, ASNs, nameservers, and entities via the RDAP protocol.
Installation
pip install rdapapi
Quick start
from rdapapi import RdapApi
api = RdapApi("your-api-key")
# Domain lookup
domain = api.domain("google.com")
print(domain.registrar.name) # "MarkMonitor Inc."
print(domain.dates.expires) # "2028-09-14T04:00:00Z"
print(domain.nameservers) # ["ns1.google.com", ...]
# IP address lookup
ip = api.ip("8.8.8.8")
print(ip.name) # "GOGL"
print(ip.cidr) # ["8.8.8.0/24"]
# ASN lookup
asn = api.asn(15169)
print(asn.name) # "GOOGLE"
# Nameserver lookup
ns = api.nameserver("ns1.google.com")
print(ns.ip_addresses.v4) # ["216.239.32.10"]
# Entity lookup
entity = api.entity("GOGL")
print(entity.name) # "Google LLC"
print(entity.autnums[0].handle) # "AS15169"
api.close()
Bulk domain lookups
Look up multiple domains in a single request (Pro and Business plans). Up to 10 domains per call, with concurrent upstream fetches:
result = api.bulk_domains(["google.com", "github.com", "invalid..com"], follow=True)
print(result.summary) # total=3, successful=2, failed=1
for r in result.results:
if r.status == "success":
print(f"{r.data.domain}: {r.data.registrar.name}")
else:
print(f"{r.domain}: {r.error}")
Each domain counts as one request toward your monthly quota. Starter plans receive a SubscriptionRequiredError (403).
Registrar follow-through
For thin registries like .com and .net, the registry only returns basic registrar info. Use follow=True to follow the registrar's RDAP link and get richer contact data:
domain = api.domain("google.com", follow=True)
print(domain.entities.registrant.organization) # "Google LLC"
print(domain.entities.registrant.email) # "registrant@google.com"
Error handling
from rdapapi import RdapApi, NotFoundError, NotSupportedError, RateLimitError, AuthenticationError
api = RdapApi("your-api-key")
try:
domain = api.domain("example.nope")
except NotSupportedError:
print("The TLD is not covered by RDAP.")
except NotFoundError:
print("The domain is not registered.")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except AuthenticationError:
print("Invalid API key")
NotSupportedError is a subclass of NotFoundError, so catching NotFoundError still handles both cases. All exceptions inherit from RdapApiError and include status_code, error, and message attributes.
| Exception | HTTP Status | When |
|---|---|---|
ValidationError |
400 | Invalid input format |
AuthenticationError |
401 | Missing or invalid API key |
SubscriptionRequiredError |
403 | No active subscription |
NotFoundError |
404 | Namespace is covered but no record exists |
NotSupportedError |
404 | Namespace (TLD, IP range, ASN range) is not covered by RDAP |
RateLimitError |
429 | Rate limit or quota exceeded |
UpstreamError |
502 | Upstream RDAP server error |
TemporarilyUnavailableError |
503 | Domain data temporarily unavailable |
Supported TLDs catalog
List every TLD the API can resolve, with the date support was added and a qualitative summary of which fields the registry's RDAP server populates. Does not count against your monthly quota.
tlds = api.tlds()
print(f"{tlds.meta.count} TLDs, coverage {tlds.meta.coverage:.0%}")
for tld in tlds.data:
availability = tld.field_availability
if availability is not None:
print(f"{tld.tld}: expires_at={availability.expires_at}")
Filter to recent additions or to a single registry:
recent = api.tlds(since="2026-04-01T00:00:00Z")
verisign = api.tlds(server="rdap.verisign.com")
Pass back the previous etag to skip the transfer when nothing has changed:
first = api.tlds()
later = api.tlds(if_none_match=first.etag)
if later is None:
print("No change since last poll")
Look up a single TLD:
com = api.tld("com")
print(com.data.rdap_server_host) # "rdap.verisign.com"
Async support
import asyncio
from rdapapi import AsyncRdapApi
async def main():
async with AsyncRdapApi("your-api-key") as api:
domain, ip, asn = await asyncio.gather(
api.domain("google.com"),
api.ip("8.8.8.8"),
api.asn(15169),
)
print(f"{domain.domain}: {domain.registrar.name}")
asyncio.run(main())
Serialization
All response objects are Pydantic models with full type hints:
domain = api.domain("google.com")
# Convert to dict
data = domain.model_dump()
# Convert to JSON string
json_str = domain.model_dump_json()
Configuration
api = RdapApi(
"your-api-key",
base_url="https://rdapapi.io/api/v1", # default
timeout=30, # seconds, default
)
Links
Development
Set up pre-commit hooks (runs lint + tests before each commit):
git config core.hooksPath .githooks
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rdapapi-0.5.0.tar.gz.
File metadata
- Download URL: rdapapi-0.5.0.tar.gz
- Upload date:
- Size: 17.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23d2659f42440b49996d502bfec28417dddd39ab98cfca324acd6dbd3b264115
|
|
| MD5 |
fb2c630e587739673d5e18f4c0bd3b44
|
|
| BLAKE2b-256 |
76ca1c14fa822d4c9d4fd448ae4e05778cf58abc9c10e83351a10d098a4df521
|
Provenance
The following attestation bundles were made for rdapapi-0.5.0.tar.gz:
Publisher:
publish.yml on rdapapi/python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rdapapi-0.5.0.tar.gz -
Subject digest:
23d2659f42440b49996d502bfec28417dddd39ab98cfca324acd6dbd3b264115 - Sigstore transparency entry: 1374681798
- Sigstore integration time:
-
Permalink:
rdapapi/python-sdk@9d473befc195c40356175b4db4f75758e65e167e -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/rdapapi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9d473befc195c40356175b4db4f75758e65e167e -
Trigger Event:
release
-
Statement type:
File details
Details for the file rdapapi-0.5.0-py3-none-any.whl.
File metadata
- Download URL: rdapapi-0.5.0-py3-none-any.whl
- Upload date:
- Size: 11.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f52e4312c160746ec3dbd94e0719684340db6a787ae664fac93c9902b9f570f9
|
|
| MD5 |
eb8ad3f388441dc290969132f6e8ee27
|
|
| BLAKE2b-256 |
ed7bee12fba1865d8712d4e941e8684d8185d233181a815e356f09ff065d6477
|
Provenance
The following attestation bundles were made for rdapapi-0.5.0-py3-none-any.whl:
Publisher:
publish.yml on rdapapi/python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rdapapi-0.5.0-py3-none-any.whl -
Subject digest:
f52e4312c160746ec3dbd94e0719684340db6a787ae664fac93c9902b9f570f9 - Sigstore transparency entry: 1374681854
- Sigstore integration time:
-
Permalink:
rdapapi/python-sdk@9d473befc195c40356175b4db4f75758e65e167e -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/rdapapi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9d473befc195c40356175b4db4f75758e65e167e -
Trigger Event:
release
-
Statement type: