Whisper · Docs
Standards

RDAP

RFC 9083 registry data over HTTPS — the machine-readable who-owns-this.

The pain

WHOIS never had a schema. Every registry formats its whois -h whois.example.net reply a little differently — free text, inconsistent field labels, no content type, no pagination, and rate limits enforced by guessing at your User-Agent. If you've ever written a regex to scrape a registration date out of a WHOIS blob, or watched it silently break when a registry re-wrapped a line, you already know why this had to be fixed. An agent deciding in milliseconds whether to trust a peer's /128 cannot afford to screen-scrape prose. It needs a typed object, a stable content type, and an HTTP status code it can branch on — which is exactly what RDAP is, and exactly why every one of Whisper's 2a04:2a01::/32 agent addresses is a first-class RDAP object, not an afterthought bolted onto DNS.

What RDAP is

RDAP (the Registration Data Access Protocol) is WHOIS's IETF-standardized replacement: plain HTTPS GET requests answered with application/rdap+json bodies. The core specs:

Whisper runs a conformant RDAP server at rdap.whisper.online for the address space we hold. Point a generic RDAP client at any of our /128s or agent names and it just works — no Whisper-specific parsing required.

The object model

Every response opens with rdapConformance (the RDAP extensions/levels in play) and an objectClassName that tells a generic client what shape to expect. For an agent's /128, that's "ip network":

{
  "rdapConformance": ["rdap_level_0"],
  "objectClassName": "ip network",
  "handle": "2A04:2A01:EB5A:CA74:CEF2:2A:323D:40D4/128",
  "startAddress": "2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4",
  "endAddress": "2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4",
  "ipVersion": "v6",
  "name": "WHISPER-AGENT-323D40D4",
  "type": "ASSIGNED",
  "country": "NL",
  "parentHandle": "2A04:2A01::/32",
  "status": ["active"],
  "entities": [
    {
      "objectClassName": "entity",
      "handle": "t9f3a1c2e7b4…",
      "roles": ["registrant"],
      "vcardArray": ["vcard", [
        ["version", {}, "text", "4.0"],
        ["fn", {}, "text", "Whisper agent tenant"]
      ]]
    },
    {
      "objectClassName": "entity",
      "handle": "WHISPER-ABUSE",
      "roles": ["abuse"],
      "vcardArray": ["vcard", [
        ["version", {}, "text", "4.0"],
        ["fn", {}, "text", "Whisper Security abuse desk"],
        ["email", {}, "text", "abuse@whisper.online"]
      ]]
    }
  ],
  "events": [
    { "eventAction": "registration", "eventDate": "2026-05-11T14:02:03Z" },
    { "eventAction": "last changed", "eventDate": "2026-06-30T09:11:47Z" }
  ],
  "links": [
    { "rel": "self", "href": "https://rdap.whisper.online/ip/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4" },
    { "rel": "up",   "href": "https://rdap.db.ripe.net/ip/2a04:2a01::/32" }
  ],
  "notices": [
    { "title": "Source", "description": ["Objects returned come from the Whisper agent registry."] }
  ]
}

Field by field, this is the whole model:

A domain object for an agent's forward name (acef2002a323d40d4.demo.agents.whisper.online) follows the identical shape, with ldhName in place of startAddress/endAddress and (when DNSSEC is configured) a secureDNS block carrying the delegation's DS/key data.

Errors are structured too — a miss returns HTTP 404 with an RFC 9083 error body, never an opaque 500:

{ "errorCode": 404, "title": "Not Found", "description": ["No RDAP object for this target."] }

The referral chain: from IANA down to a /128

RDAP is designed to be walked, not memorized — and you do not need to know Whisper's RDAP server exists to find one of our agents. A general-purpose client starts at IANA's RFC 9224 bootstrap registry, learns that 2a04:2a01::/32 is served by rdap.db.ripe.net, and queries RIPE — which authoritatively names the block WHISPER-AGENTS (viaGraph b.v.), with no Whisper-specific knowledge required. RIPE holds and answers for the whole /32; it does not hand the query down to us, so to reach the individual /128 — the specific agent, its status, its registrant — you then query rdap.whisper.online, whose up link points straight back at the RIPE object. Either way the chain is unbroken and machine-walkable from the IANA root all the way to the exact agent, with no step that requires trusting our prose.

RDAP is one of the seven keyless verification proofs — no account, no SDK, just HTTPS. It composes with DANE (who signs the TLS key) and the transparency log (when that key was issued) to answer "is this really a Whisper agent" without ever trusting our API to tell the truth.

Ownership history

A /128 can be released and re-allocated, so the registry keeps every holder, not just the current one. It's exposed on the IP object itself as two query parameters — ?history for the full array of ownership intervals, ?time=<instant> for the single holder at a moment — so it needs no special client:

# stock tools: every ownership interval, straight off the endpoint
curl -s 'https://rdap.whisper.online/ip/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4?history' | jq '.history'

# stock tools: the holder at a past instant (RFC 3339)
curl -s 'https://rdap.whisper.online/ip/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4?time=2026-05-01T00:00:00Z' | jq '{handle, status, entities}'

# the CLI wraps the same two parameters as flags
whisper rdap 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 --history   # every ownership interval
whisper rdap 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 --at 2026-05-01T00:00:00Z  # the holder at that instant

Handles on that trail are always opaque per-tenant identifiers — never a raw account ID — the same way dig -x never leaks anything beyond a hostname.

Try it — with stock tools, and with Whisper

With stock tools (no Whisper software — any RDAP-aware client works identically against any registry):

# discover it cold — no knowledge of Whisper's RDAP server needed. A generic client follows
# the IANA bootstrap (RFC 9224) to the RIR that holds the block; rdap.org is one public
# redirector that does the walk for you. It lands on RIPE, which names the space:
curl -sL https://rdap.org/ip/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 | jq '{handle, name, remarks}'
# -> handle "2a04:2a01::/32", name "WHISPER-AGENTS",
#    remark "Whisper agent identity space (viaGraph b.v.) - per-/128 assignments"

# then the specific /128 — the individual agent — from Whisper's own RDAP (its `up` link
# points back at that RIPE object, so the chain is complete). RFC 9083 JSON:
curl -s -H 'Accept: application/rdap+json' \
  https://rdap.whisper.online/ip/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 | jq '{handle, status, entities, events}'

# the domain object, for the agent's forward name
curl -s https://rdap.whisper.online/domain/acef2002a323d40d4.demo.agents.whisper.online | jq '{ldhName, status, links}'

# the legacy port-43 protocol, RFC 3912, same record
whois -h whois.whisper.online 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4

# the keyless full-chain verdict — no key, no SDK
curl -s https://rdap.whisper.online/verify-identity/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 \
  | jq '{is_whisper_agent, dane_ok, jws_ok}'

With Whisper (the CLI wraps the same endpoints, always emits the raw RDAP JSON — it's the data, not a summary):

whisper rdap 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4              # IP object
whisper rdap acef2002a323d40d4.demo.agents.whisper.online        # domain object
whisper rdap 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 --history     # ownership trail

whisper verify --trustless 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 # re-derives RDAP + DANE + the
                                                                  # transparency log itself, anchored
                                                                  # at the IANA DNSSEC root — the
                                                                  # Whisper API is never trusted

Both paths hit the same public server and get the same bytes back; the CLI just saves you the curl/jq boilerplate and adds --trustless re-derivation for when you don't want to trust us to tell you the truth about ourselves. The whisper_rdap tool ships in the MCP server too, so an agent can look up a peer's RDAP record as a native tool call rather than shelling out.

Next