Build on mosskeys
Publish verifiable, append-only key histories from your backend or an agent, and let anyone read and verify them. Two APIs, one honest log: an authenticated write path you push public key material to, and a public read and verify API that returns independently checkable proofs.
New to mosskeys?
Start with the quickstart and worked integration examples, then dive into the reference.
Write API
Append public keys and publish client-signed checkpoints from a service or agent, with idempotent retries, capability-scoped tokens, and Bring-Your-Own-Key checkpoint signing.
Read & verify API
Fetch a key, pull an RFC 6962 inclusion proof, and verify it against a client-signed checkpoint, or run a privacy-preserving lookup for a presence or absence proof. No token required. The same bytes witnesses and CDNs consume.
Run a witness
Not publishing logs, but guarding them: run standard C2SP witness software on your own infrastructure and cosign mosskeys checkpoints as an independent party. Software, keys, hosting, applying, going live.
Zero-knowledge guarantees
mosskeys is designed so that secrets never leave your infrastructure. Everything the APIs move is either already public or something you signed locally first.
- Only already-public material crosses the wire: public keys, the tree size and root, and checkpoint notes you have already signed locally with your own key.
- The server never signs anything. Checkpoint signing is Bring-Your-Own-Key (BYOK) and happens entirely on your side. The server only verifies a signed note and checks that it commits to the log's current head before persisting it.
- Your signing key is read locally, used locally, and never transmitted or logged. API tokens authenticate who is writing; they are never signing keys and can never unlock encrypted data.
- Labels — the one field that names an identity — are encrypted at rest (AES-256-GCM) and matched through a keyed blind index, so a database dump reveals neither who is in your log nor which labels repeat across namespaces. Public APIs never serve labels except back to the party that already knew the label.
- Directory lookups are oblivious by default (RFC 9497 POPRF on current namespaces): your client blinds the label, the server evaluates only the blinded element, and you unblind and verify the proof locally — so the server never sees which label you looked up. Two honest caveats: the blinding is classical cryptography (ristretto255), so recorded evaluation transcripts are not post-quantum private; and the operator can always dictionary low-entropy labels offline, which is inherent to any server-keyed deterministic index. Legacy VRF namespaces still see the queried label at query time until their owner upgrades (one-way, in the namespace's policy section).
The mental model
A mosskeys namespace is a single append-only transparency log. Its slug (for example acme) is the
public handle used in every URL below. The log has two sides:
- You append leaves. Each leaf is the public key material for one identity (a person, service, or agent). Appends are authenticated and idempotent.
- You publish checkpoints. A checkpoint is a signed tree head: a commitment to the whole log at a point in time, signed by your key. Verifiers pin to it.
- Anyone reads and verifies. The public API serves leaves, checkpoints, and RFC 6962 proofs so a client can prove a key is genuinely in the log the checkpoint committed to, without trusting the server. An oblivious lookup (RFC 9497 POPRF) can also prove a label's newest key, or its absence, without the server seeing which label you asked about.
Base URL
Every path in these docs is relative to the base URL and a namespace slug.
https://mosskeys.com
So the append endpoint for the namespace
acme
is POST https://mosskeys.com/api/acme/log/entries,
and its latest checkpoint is at GET https://mosskeys.com/api/acme/checkpoint.