Documentation

Getting started

Instrument an agent to produce verifiable, tamper-proof receipts in about five minutes.

What is Zanii

Zanii is a transparency log for AI agents. Every agent gets a cryptographic identity (did:key), delegated by its owner. Each action becomes a signed, hash-chained receipt in an append-only Merkle log whose state is anchored on-chain. Anyone can verify a receipt — signature, delegation, scope, inclusion — offline, with no trust in Zanii. Receipts store only a hash of your payload, so no business data leaves your systems.

Install

# TypeScript / JavaScript
npm install @zanii/sdk

# Python
pip install zanii
Reads (proofs, verification, badges) are public and need no key. To write receipts, create an account and issue a key in seconds — see Accounts & API keys.

Quickstart (TypeScript)

1 — create an owner and agent identity, and an owner-signed delegation granting the agent scoped authority:

import { generateKeypair, createCert, ZaniiAgent } from '@zanii/sdk';

const owner = generateKeypair();
const agent = generateKeypair();
const cert  = createCert(
  { issuer: owner.did, subject: agent.did, scopes: ['email.*', 'crm.read'], exp: '2027-01-01T00:00:00.000Z' },
  owner.privateKey);

2 — wrap your tools. Every call is signed and shipped to the log automatically:

const zanii = new ZaniiAgent({
  serverUrl: 'https://ledger.zanii.agency',
  agentDid: agent.did, agentPrivateKey: agent.privateKey,
  delegation: [cert],
  apiKey: process.env.ZANII_API_KEY,
});

const sendEmail = zanii.wrapTool('email.send', realSendEmail);
await sendEmail('jane@acme.co', 'Your invoice');   // recorded + provable
await zanii.flush();

Core concepts

Verifying proofs (zero trust)

Anyone can fetch a receipt’s proof and verify it entirely client-side — signature, delegation, scope, Merkle inclusion, and the signed tree head:

import { fetchAndVerifyProof } from '@zanii/sdk';

const report = await fetchAndVerifyProof('https://ledger.zanii.agency', receiptHash);
console.log(report.ok);   // true — verified without trusting the server

Every receipt also has a shareable, human-readable proof page at /verify/<hash>.

Audit bundles

Export an agent’s complete, offline-verifiable history — receipts, proofs, revocations, and anchors — as a single file: GET /v1/export/:agentDid. Verify it anywhere with verifyAuditBundle(). Useful for compliance evidence (EU AI Act record-keeping, SOC 2).

Accounts & API keys (self-serve)

Reads are public and need no key. Writing receipts needs an API key — create an account and issue your own, no waiting. The admin key (zk_admin_) manages your account; the ingest key (zk_live_) writes receipts. Both are shown once.

# 1. sign up — save the admin key
curl -X POST https://ledger.zanii.agency/v1/account/signup   -H 'content-type: application/json' -d '{"name":"Acme AI"}'
#   → { "org_id": 1, "admin_key": "zk_admin_…" }

# 2. issue an ingest key (send the admin key as a Bearer token)
curl -X POST https://ledger.zanii.agency/v1/account/keys   -H 'authorization: Bearer zk_admin_…' -d '{"label":"prod"}'
#   → { "api_key": "zk_live_…" }  — pass as apiKey (TS) / api_key (Python)

Manage your account (all require the admin key):

Webhooks

Get notified when your agents act. Register an https endpoint and Zanii POSTs a signed JSON event to it. Events: receipt.recorded (an agent recorded an action) and receipt.rejected (a write was rejected — e.g. out of scope, or a revoked delegation).

curl -X POST https://ledger.zanii.agency/v1/account/webhooks   -H 'authorization: Bearer zk_admin_…'   -d '{"url":"https://your-app.com/zanii","events":["receipt.recorded","receipt.rejected"]}'
#   → { "id": 1, "secret": "whsec_…" }   (secret shown once)

Every delivery carries an X-Zanii-Event header and an X-Zanii-Signature header. Always verify the signature before trusting a delivery — it is sha256= followed by the HMAC-SHA256 of the raw request body, keyed with your secret:

import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(rawBody, signature, secret) {
  const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex');
  return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

Payload shape:

{ "event": "receipt.recorded",
  "ts": "2026-07-04T13:00:00.000Z",
  "data": { "hash": "sha256:…", "index": 42, "agent_id": "did:key:…",
           "action": "tool_call", "target": "crm.lookup" } }

Manage with GET /v1/account/webhooks and DELETE /v1/account/webhooks/{id}. Only public https URLs are accepted; delivery is best-effort with retries.

Public pages & embeds

Everything below is public — no key, no login. Great for dashboards, live demos, and sharing.

Learn more