Base URL https://ledger.zanii.agency. JSON. CORS: the API sends no Access-Control-Allow-Origin header, so browsers must call it same-origin — the frontend proxies /v1/* via next.config.mjs. All /v1/ data endpoints are stable.
Auth
Authorization: Bearer <token>. Ingest key zk_live_ (writes). Admin key zk_admin_ (account mgmt). Reads/proofs/stats/stream/badges: public, no key.
Reads (public)
GET /v1/stats→{ receipts, agents, anchors, last_anchor_ts, last_receipt_ts }GET /v1/recent?limit=20(max 100) →{ receipts: [{ receipt, hash, index, parties[] }] }(newest first)GET /v1/stream→ SSE:event: hello{size}, thenevent: receiptper new receipt{ hash, index, parties, action, target, ts, type }GET /v1/sth→{ v, log_id, size, root, ts, sig }(Signed Tree Head)GET /v1/proof/{hash}→{ receipt, hash, index, proof[], sth }(Merkle inclusion proof; 404 if unknown)GET /v1/consistency?first={size}→ append-only prefix proofGET /v1/head/{did}→{ head: "sha256:…" | null }GET /v1/agents→{ agents: [{ agent_id, owner, count, head, last_ts, revoked }] }GET /v1/anchors→{ anchors: [{ sth, backend:"evm", ref:"0x…", block, anchored_at }] }GET /v1/revocations→{ revocations: [{ cert_hash, index, ts }] }GET /v1/reputation/{did}→{ agent_id, owner, receipts, a2a_interactions, distinct_counterparties, first_ts, last_ts, revoked, fully_anchored, audit_bundle }(404 if none)GET /v1/export/{did}→ self-contained audit bundle (receipts + proofs + revocations + anchors + STH)
Account API (admin key) — §3
POST /v1/account/signup {name}→{ org_id, name, admin_key }(admin_key shown once)GET /v1/account/me→{ org_id, name, plan, active_keys, usage_30d }GET /v1/account/keys→{ keys: [{ id, label, scopes[], created_at, last_used_at, revoked }] }POST /v1/account/keys {label, scopes:["write"]}→{ api_key, label, scopes }(api_key once)DELETE /v1/account/keys/{id}→{ revoked, id }GET /v1/account/usage?since=YYYY-MM-DD→{ since, total, by_day: [{ day, count }] }- Webhooks:
GET/POST/DELETE /v1/account/webhooks({url, events:["receipt.recorded","receipt.rejected"]};secretonce)
Ingest (zk_live_)
POST /v1/receipts {receipts:[SignedReceipt]}(batch ≤100, idempotent by hash)POST /v1/interactions(cross-org co-signed),POST /v1/revocations(cert issuer-signed)
Data models
Receipt: { v, agent_id:"did:key:…", delegation:[DelegationCert], action, target, payload_hash:"sha256:…", ts, prev, sig } — payload never leaves your systems, only its hash.
DelegationCert: { v, issuer, subject, scopes[], exp, sig }.
Identities = did:key (Ed25519, DID is the public key). Hashes = SHA-256 over RFC 8785 JCS, prefixed sha256:.
Public product surface (no key)
GET /badge/{did}.svg, GET /qr/{hash}.svg, GET /agent/{did} (HTML OG card), GET /verify/{hash} (HTML), GET /dashboard, GET /health.
SDKs
TS npm i @zanii/sdk (+ @zanii/core, @zanii/mcp-proxy). Python pip install zanii.