# Point-in-time RDAP

**Standard RDAP answers who owns this right now. This is the keyless flow for who we observed as the operator of record at a specific time, T, with a proof that folds to the same signed checkpoint as everything else in the log.**

> **Status today: built, not switched on.** Every endpoint below is real code, live-routed, and returns a clean, honest `404` explaining exactly that - `whisper.ns.ledger.observations.enabled` defaults to `false` and neither production node has turned it on yet, so no observation has ever been minted. The rest of this page describes the mechanism as designed - the schema, the receipt format, the endpoints - so you know exactly what to expect when it's enabled, not what you'll get if you query it right now. See [What's live today](#whats-live-today) for the current, verifiable state.

## What point-in-time RDAP is

[RDAP](/docs/rdap) is current-state only: query an IP, a domain, or an autonomous system number and you get today's answer. There is no standard way to ask "who was it in May." Whisper's [transparency log](/docs/transparency) already keeps a tamper-evident, append-only record of everything it issues, so instead of standing up a second history store, Whisper records what an RDAP query showed, and when, as one more leaf in that same tree, then serves it back through a small "as of T" extension of the ordinary RDAP object model.

The result composes with the other proofs on this site: the object you get back is standard [RFC 9083](/docs/rdap) JSON, and it carries a [SCITT receipt](/docs/scitt-receipts) you fold offline to the exact same root as `/checkpoint`. One log, three surfaces (identity, SCITT receipts, and this one), never a second source of truth.

## The honest data model: an observation, not a registry edit

Each time Whisper looks at a subject, it records what it saw, not what changed: *we observed `<subject>` to have operator-of-record `X`, ASN `Y`, status `Z`, at time `T`.* That observation becomes one more leaf kind in the [same tree](/docs/transparency) that already holds identity issuance and revocation events: same salted-commitment leaf rule, same single append-only log, same signed checkpoint chain, same key. Nothing about the tree changes shape to hold it; it just grows.

That framing matters for what you can trust. The leaf commits to *what we observed*, unaltered since. It does not, and cannot, commit to the registry's own ground truth, because RDAP itself carries no registry signature to anchor to (more on that below).

## The keyless flow

No API key. Ask for a subject and, optionally, a time:

| Endpoint | Returns |
|---|---|
| `GET /history/ip/<addr>[?at=<T>]` | observed operator/ASN/status history for an IP or `/128` |
| `GET /history/domain/<name>[?at=<T>]` | observed history for a domain |
| `GET /history/autnum/<asn>[?at=<T>]` | observed history for an AS number |
| `GET /operator-of-record/<subject>[?at=<T>]` | friendly alias for any of the three |

`Accept: application/rdap+json`. Omit `?at=` and you get the full observed history, oldest first; supply it and the answer collapses to the single observation current at that instant, the latest one whose `applicableFrom` is at or before `T`.

```bash
curl -s -H 'Accept: application/rdap+json' \
  'https://whisper.online/history/ip/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4?at=2026-07-01T00:00:00Z'
```

Run today, that returns the honest not-enabled answer (see [What's live today](#whats-live-today)). The designed shape - what it returns once minting is turned on - is:

```json
{
  "rdapConformance": ["rdap_level_0", "history_0", "whisper_ledger_0"],
  "objectClassName": "history",
  "records": [
    {
      "applicableFrom": "2026-05-11T14:02:03Z",
      "content": {
        "objectClassName": "ip network",
        "handle": "acef2002a323d40d4",
        "status": ["active"],
        "entities": [
          { "objectClassName": "entity", "roles": ["registrant"], "handle": "{tenant}" }
        ]
      },
      "whisperReceipt": "0oRDoQEmoQrAQ7hg9…",
      "provenance": "first-party"
    }
  ]
}
```

`content` is an ordinary [RFC 9083](/docs/rdap) object, exactly what a current-state RDAP query would have returned at that moment. `whisperReceipt` is the [SCITT receipt](/docs/scitt-receipts) for that observation's leaf, base64-encoded COSE: fold its inclusion proof offline and it byte-equals the served `/checkpoint` root at that tree size, the same fold as every other proof on this log. `provenance` says whether Whisper itself operates the subject (`first-party`) or the observation came from watching someone else's RDAP answer (`observed-external`).

A domain query follows the same shape, keyed by name instead of address:

```bash
curl -s -H 'Accept: application/rdap+json' \
  'https://whisper.online/operator-of-record/yourdomain.example?at=2026-07-01T00:00:00Z'
```

## `?at=` is our extension, not a standard

RDAP has no "as of" query parameter in RFC 9082. `?at=` (RFC 3339, epoch milliseconds, or a relative offset like `-7d`, all accepted; `?time=` also works, matching [the existing per-`/128` ownership history](/docs/rdap#ownership-history)) is Whisper's own extension, declared honestly via the `whisper_ledger_0` entry in `rdapConformance` so a generic client can tell it apart from IETF-standard behavior. Nothing here claims IETF blessing for the parameter itself; the object shape it returns follows the (expired, individual) `draft-ellacott-historical-rdap` sketch of a `history` object class, because reusing a real proposal beats inventing a fourth format.

## The boundary: what this attests

> Whisper attests that we observed this RDAP answer for the subject at that time, and that it has been unaltered since: a time-anchored, tamper-evident record of what we saw, provable against the signed checkpoint. It is not a statement that the registry's data was correct, and it does not carry the registry's own signature, because RDAP has none ([RFC 7481 §3.6](https://www.rfc-editor.org/rfc/rfc7481#section-3.6), "Data Integrity"). For subjects Whisper itself operates (`2a04:2a01::/32`, AS219419) the observation is also first-party authoritative: we are the registry, so what we observed and the registry's own truth are the same fact.

## Coverage, honestly

Three cases where a lesser system would guess; this one says so instead:

- **No RDAP source for the subject.** Not every corner of the namespace runs RDAP yet, and RFC 9224's IANA bootstrap registry is the source of truth for who does. A subject with no discoverable RDAP source gets a `notices` entry saying so, never a fabricated operator.
- **`T` before the first observation.** A plain, honest 404: no observation of that subject at or before that time, not an empty-looking 200.
- **A status Whisper hasn't indexed.** Treated as "not revoked," never invented outright.

## What's live today

The mechanism above is built and code-reviewed - the endpoints route, the observation collector, the receipt format, and the `history_0` RDAP extension all exist in the tree - but minting is switched off in production. The gate is one flag, `whisper.ns.ledger.observations.enabled` (default `false`), and neither `ns1` nor `ns2` has it set today, so no observation has ever actually been written to the log:

```bash
curl -s -w '\nHTTP:%{http_code}\n' -H 'Accept: application/rdap+json' \
  'https://whisper.online/history/ip/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4?at=2026-07-01T00:00:00Z'
```
```
{"rdapConformance":["rdap_level_0"],"errorCode":404,"title":"Not Found","description":["point-in-time RDAP observations are not enabled on this node (whisper.ns.ledger.observations.enabled=false)"]}
HTTP:404
```

Every query - `/history/ip`, `/history/domain`, `/history/autnum`, `/operator-of-record`, on either node, with or without `?at=` - returns that same clean `404`, and it says exactly why: this is the fail-closed, self-defending guard the code names, not a bug. It is honest in the way the rest of this page insists on: never a fabricated observation, never a silent empty array standing in for "off." When the flag flips, coverage starts where the page above describes - Whisper's own `2a04:2a01::/32` and AS219419 first, since those observations are first-party from day one - and this section will be rewritten to a live capture at that point, not before.

## Next

[Transparency log](/docs/transparency) for the tree this rides on, [SCITT receipts](/docs/scitt-receipts) for the receipt format folded above, or [RDAP](/docs/rdap) for the current-state object model this extends.
