# `GET /.well-known/converg3nce-keys.json`

The public keys for verifying signed [verification records](verify.md).

```
GET https://api.converg3nce.com/.well-known/converg3nce-keys.json
```

**No authentication.** This is the deliberate public exception in an otherwise key-gated
API: a signature nobody can check is not a signature.

`Cache-Control: public, max-age=300, s-maxage=3600`

## Response

```json
{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "<base64url>",
      "kid": "c3n-default",
      "use": "sig",
      "alg": "EdDSA"
    }
  ]
}
```

Standard JWKS shape. The active key is first, followed by any retired keys still inside
their **90-day** verification window — so records signed before a rotation stay
verifiable.

An empty `keys` array means no signing key is configured. Every record from that
deployment will be unsigned.

## Verifying a record

1. Fetch the record from [`/v1/verify`](verify.md).
2. **Confirm `signature` is present.** Absent means unsigned — treat as unverified.
3. Fetch this key set and select the key whose `kid` matches the record's `key_id`.
4. Remove `key_id` and `signature` from the record.
5. Canonicalize what remains as RFC 8785 JSON.
6. Verify the Ed25519 signature over those bytes.

Steps 4 and 5 are the ones that go wrong: the signature covers the canonical form of the
record *without* those two fields, so re-serializing the record as received will not
verify.
