{"id":45961250,"url":"https://github.com/rdapapi/python-sdk","last_synced_at":"2026-04-24T23:01:35.700Z","repository":{"id":340639941,"uuid":"1165826337","full_name":"rdapapi/python-sdk","owner":"rdapapi","description":"Official Python SDK for the RDAP API — look up domains, IPs, ASNs, nameservers, and entities. Clean typed responses with sync and async support.","archived":false,"fork":false,"pushed_at":"2026-02-28T10:37:33.000Z","size":26,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-02T16:46:37.517Z","etag":null,"topics":["python","rdap","rdap-service"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rdapapi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-24T15:32:35.000Z","updated_at":"2026-02-28T10:37:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rdapapi/python-sdk","commit_stats":null,"previous_names":["rdapapi/python-sdk"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/rdapapi/python-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdapapi%2Fpython-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdapapi%2Fpython-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdapapi%2Fpython-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdapapi%2Fpython-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rdapapi","download_url":"https://codeload.github.com/rdapapi/python-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdapapi%2Fpython-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32243803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T13:21:15.438Z","status":"ssl_error","status_checked_at":"2026-04-24T13:21:15.005Z","response_time":64,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["python","rdap","rdap-service"],"created_at":"2026-02-28T13:50:06.761Z","updated_at":"2026-04-24T23:01:35.694Z","avatar_url":"https://github.com/rdapapi.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RDAP API Python SDK\n\n[![PyPI version](https://img.shields.io/pypi/v/rdapapi.svg)](https://pypi.org/project/rdapapi/)\n[![Python versions](https://img.shields.io/pypi/pyversions/rdapapi.svg)](https://pypi.org/project/rdapapi/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\nOfficial Python SDK for the [RDAP API](https://rdapapi.io) — look up domains, IP addresses, ASNs, nameservers, and entities via the RDAP protocol.\n\n## Installation\n\n```bash\npip install rdapapi\n```\n\n## Quick start\n\n```python\nfrom rdapapi import RdapApi\n\napi = RdapApi(\"your-api-key\")\n\n# Domain lookup\ndomain = api.domain(\"google.com\")\nprint(domain.registrar.name)     # \"MarkMonitor Inc.\"\nprint(domain.dates.expires)      # \"2028-09-14T04:00:00Z\"\nprint(domain.nameservers)        # [\"ns1.google.com\", ...]\n\n# IP address lookup\nip = api.ip(\"8.8.8.8\")\nprint(ip.name)                   # \"GOGL\"\nprint(ip.cidr)                   # [\"8.8.8.0/24\"]\n\n# ASN lookup\nasn = api.asn(15169)\nprint(asn.name)                  # \"GOOGLE\"\n\n# Nameserver lookup\nns = api.nameserver(\"ns1.google.com\")\nprint(ns.ip_addresses.v4)       # [\"216.239.32.10\"]\n\n# Entity lookup\nentity = api.entity(\"GOGL\")\nprint(entity.name)               # \"Google LLC\"\nprint(entity.autnums[0].handle) # \"AS15169\"\n\napi.close()\n```\n\n## Bulk domain lookups\n\nLook up multiple domains in a single request (Pro and Business plans). Up to 10 domains per call, with concurrent upstream fetches:\n\n```python\nresult = api.bulk_domains([\"google.com\", \"github.com\", \"invalid..com\"], follow=True)\n\nprint(result.summary)  # total=3, successful=2, failed=1\n\nfor r in result.results:\n    if r.status == \"success\":\n        print(f\"{r.data.domain}: {r.data.registrar.name}\")\n    else:\n        print(f\"{r.domain}: {r.error}\")\n```\n\nEach domain counts as one request toward your monthly quota. Starter plans receive a `SubscriptionRequiredError` (403).\n\n## Registrar follow-through\n\nFor 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:\n\n```python\ndomain = api.domain(\"google.com\", follow=True)\nprint(domain.entities.registrant.organization)  # \"Google LLC\"\nprint(domain.entities.registrant.email)         # \"registrant@google.com\"\n```\n\n## Error handling\n\n```python\nfrom rdapapi import RdapApi, NotFoundError, NotSupportedError, RateLimitError, AuthenticationError\n\napi = RdapApi(\"your-api-key\")\n\ntry:\n    domain = api.domain(\"example.nope\")\nexcept NotSupportedError:\n    print(\"The TLD is not covered by RDAP.\")\nexcept NotFoundError:\n    print(\"The domain is not registered.\")\nexcept RateLimitError as e:\n    print(f\"Rate limited. Retry after {e.retry_after}s\")\nexcept AuthenticationError:\n    print(\"Invalid API key\")\n```\n\n`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.\n\n| Exception | HTTP Status | When |\n|-----------|------------|------|\n| `ValidationError` | 400 | Invalid input format |\n| `AuthenticationError` | 401 | Missing or invalid API key |\n| `SubscriptionRequiredError` | 403 | No active subscription |\n| `NotFoundError` | 404 | Namespace is covered but no record exists |\n| `NotSupportedError` | 404 | Namespace (TLD, IP range, ASN range) is not covered by RDAP |\n| `RateLimitError` | 429 | Rate limit or quota exceeded |\n| `UpstreamError` | 502 | Upstream RDAP server error |\n| `TemporarilyUnavailableError` | 503 | Domain data temporarily unavailable |\n\n## Supported TLDs catalog\n\nList 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.\n\n```python\ntlds = api.tlds()\nprint(f\"{tlds.meta.count} TLDs, coverage {tlds.meta.coverage:.0%}\")\n\nfor tld in tlds.data:\n    availability = tld.field_availability\n    if availability is not None:\n        print(f\"{tld.tld}: expires_at={availability.expires_at}\")\n```\n\nFilter to recent additions or to a single registry:\n\n```python\nrecent = api.tlds(since=\"2026-04-01T00:00:00Z\")\nverisign = api.tlds(server=\"rdap.verisign.com\")\n```\n\nPass back the previous `etag` to skip the transfer when nothing has changed:\n\n```python\nfirst = api.tlds()\nlater = api.tlds(if_none_match=first.etag)\nif later is None:\n    print(\"No change since last poll\")\n```\n\nLook up a single TLD:\n\n```python\ncom = api.tld(\"com\")\nprint(com.data.rdap_server_host)  # \"rdap.verisign.com\"\n```\n\n## Async support\n\n```python\nimport asyncio\nfrom rdapapi import AsyncRdapApi\n\nasync def main():\n    async with AsyncRdapApi(\"your-api-key\") as api:\n        domain, ip, asn = await asyncio.gather(\n            api.domain(\"google.com\"),\n            api.ip(\"8.8.8.8\"),\n            api.asn(15169),\n        )\n        print(f\"{domain.domain}: {domain.registrar.name}\")\n\nasyncio.run(main())\n```\n\n## Serialization\n\nAll response objects are [Pydantic](https://docs.pydantic.dev/) models with full type hints:\n\n```python\ndomain = api.domain(\"google.com\")\n\n# Convert to dict\ndata = domain.model_dump()\n\n# Convert to JSON string\njson_str = domain.model_dump_json()\n```\n\n## Configuration\n\n```python\napi = RdapApi(\n    \"your-api-key\",\n    base_url=\"https://rdapapi.io/api/v1\",  # default\n    timeout=30,                              # seconds, default\n)\n```\n\n## Links\n\n- [API Documentation](https://rdapapi.io/docs)\n- [Get an API Key](https://rdapapi.io/register)\n- [OpenAPI Spec](https://rdapapi.io/openapi.yaml)\n- [Pricing](https://rdapapi.io/pricing)\n\n## Development\n\nSet up pre-commit hooks (runs lint + tests before each commit):\n\n```bash\ngit config core.hooksPath .githooks\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frdapapi%2Fpython-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frdapapi%2Fpython-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frdapapi%2Fpython-sdk/lists"}