# Keyless Endpoints

> Whisper's keyless HTTP surface: the verify-identity verdict, RDAP records, the egress echo, and every transparency log path with its parameters.

*Source: https://www.whisper.security/docs/control-plane/keyless*

---
Every path on this page answers with no key and no account, on `https://rdap.whisper.online`. That is what lets a stranger check an identity you minted without asking you for anything.

## Verify an identity

```bash
curl -s 'https://rdap.whisper.online/verify-identity?ip=2a04:2a01:b69a:6717:e3b0:51ff:3bf7:f478'
```

One call runs the whole proof chain and returns one verdict. The target can also be a path segment, as in `/verify-identity/<address>`, and the query parameter may be named `ip`, `address`, `addr`, `fqdn`, `name` or `host`.

| Field | Holds |
|---|---|
| `is_whisper_agent` | The verdict. |
| `fqdn` | The canonical name the address resolves to and back from. |
| `operator` | Who operates the identity. |
| `tenant` | The account handle, in the form `t<tenant>`. |
| `dane_ok` | Whether the served certificate matches the pinned key. |
| `jws_ok` | Whether the signed identity document checks out. |
| `verified_at` | When the checks were run. |
| `evidence` | Every check, with what it read. |

An address that is not a Whisper identity answers `200` with `is_whisper_agent` false, which is an answer rather than a failure. A malformed target answers `400` with a `detail` saying why. The response is never cached.

### Inside evidence

| Field | Holds |
|---|---|
| `address` | The address checked. |
| `ptr` | The reverse name found for it. |
| `forward_aaaa` | The address the forward name resolves to. |
| `agent` | The identifier behind the address. |
| `allocated_at` | When it was allocated. |
| `posture` | The posture recorded on the identity. |
| `dane_tlsa_sha256` | The digest published in the pin. |
| `dane` | The pin itself, as `usage`, `selector`, `matching`, `strong_pin` and `served_leaf_matches`. |
| `rdap` | What the registry holds. |
| `identity_doc` | What the signed identity document says. |

[Verify an identity](/docs/identity/verify) runs the same checks with stock tools, one at a time.

## The registry

| Path | Answers |
|---|---|
| `GET /ip/<address>` | The registry record for one address, as RFC 9083 `application/rdap+json`. |
| `GET /domain/<name>` | The registry record for a name. |
| `GET /ip/<address>/transparency` | The log entries for that one address. |

A record carries a `handle`, a `name`, a `type` of `Whisper agent identity`, a `status`, a `startAddress` and an `endAddress` that are the same address, and an `rdap-up` link to the regional registry above it. An address with no identity answers an RFC 9083 error object with `errorCode` 404.

Add `?at=` or `?time=` to read the record as it stood earlier. It accepts an RFC 3339 timestamp, epoch milliseconds, or a relative offset.

The transparency read returns `object`, `address`, `count`, `events`, `root_hash`, `root_signature` and `root_signature_alg`, and takes `limit`, `from` and `to`. [RDAP and WHOIS](/docs/identity/registry) covers the registry itself and its other front doors.

## Prove a source address

```bash
curl -s https://rdap.whisper.online/egress-ip
```

The echo returns `{"ip": "..."}` for whichever address the request arrived from. Add `?format=` or send `Accept: text/plain` for the bare address.

## The transparency log

Issuance and revocation are written to a tamper-evident, signed transparency log. These paths read it.

| Path | Answers |
|---|---|
| `GET /checkpoint` | The current signed checkpoint. |
| `GET /checkpoint/key` | The log's signing key, as `object`, `origin`, `alg`, `key_id`, `public_key` and `public_key_spki`. |
| `GET /checkpoint/status-list` | The signed revocation status list. |
| `GET /checkpoint/ots` | The Bitcoin anchoring for the current checkpoint. |
| `GET /checkpoint/ots/latest-confirmed` | The most recent anchoring that has confirmed. |
| `GET /tile/<level>/<index>` | One tile of the tree. A tile that is not there answers `404`. |
| `GET /inclusion?leaf=<n>` | Proof that one leaf is in the tree, as `leaf`, `tree_size`, `leaf_hash`, `proof` and `checkpoint`. A leaf that does not exist answers `400`. The parameter may also be named `index` or `n`, and takes a decimal position or a hex digest. |
| `GET /consistency?from=<n>&to=<n>` | Proof that the tree at `to` extends the tree at `from`. Both parameters are required, and no other names are accepted. |
| `GET /entries/<leaf>` | The stored statement, as `application/cose`, with the entry named in the `X-Whisper-Scitt-Entry` header. A `204` means the entry is recorded and a proof for it is not available. |
| `GET /.well-known/scitt-keys` | The keys a receipt is checked against. |

Every answer carries an `X-Whisper-Ledger-Claim` header stating the assurance the log currently offers. The signing key is also published in DNS as `TXT _whisper-ledger.whisper.online`, and the origin string a verifier checks against is `whisper.online/ledger/g2`.

A proof path can answer `503` while the log is still catching up to the tree. Wait for the interval the response gives, then ask again.

[The transparency log](/docs/identity/transparency) explains what a leaf is and why a record can be shredded without breaking a proof.

## Writing to the log

Two doors take a key. Both are on the same host.

| Path | Takes | Answers |
|---|---|---|
| `POST /entries` | A COSE signed statement. | `202` and a `Location` header pointing at the entry. |
| `POST /attest` | JSON with `control_id`, `verdict`, `evidence_hash` and `framework`. | `leaf_index`, `receipt`, `checkpoint` and `canonical`. |

A call with no key answers `401 missing_api_key`, and one with a key the plane does not know answers `403 invalid_api_key`. A malformed body answers `400`. Failures on these two paths are concise problem details in CBOR rather than the envelope described in [The request envelope](/docs/control-plane/envelope).
