Prove what your AI agent did without sharing your database
Sign a checkpoint of your agent audit log, mint a receipt for one decision, and let a counterparty verify it offline with a public key. Runnable TypeScript.
A customer asks whether your agent really approved that refund, and “trust our logs” is a weak answer. Giving them database access is worse. A signed checkpoint and a receipt let them check one decision themselves, offline, with a public key.This tutorial signs a checkpoint of an audit log, mints a receipt that reveals four fields and hides the rest, verifies it the way a counterparty would, and then proves a later checkpoint extends the first. It runs in memory with no model and no API key.
You, the operator, generate a key pair, sign the head of the log, and cut a receipt for decision-2 that reveals only the action, resource, result and timestamp.
const keys = await generateCheckpointKeyPair("audit-2026-10");const first = await createCheckpoint(auth.db, { signer: keys.signer });if (!first.success) throw new Error(first.error.message);console.log(`checkpoint: size=${first.data.size} root=${first.data.rootHash.slice(0, 16)}...`);const receipt = await createReceipt(auth.db, "decision-2", first.data, { reveal: ["action", "resource", "result", "timestamp"],});if (!receipt.success) throw new Error(receipt.error.message);const wire = JSON.stringify(receipt.data);console.log(`receipt is ${wire.length} bytes and hides the parameters`);
Keep the private key in your secret store and publish keys.publicKey.
Real output from the example. Your root hash and receipt size will differ, because the rows carry timestamps from your run.
checkpoint: size=3 root=0a12313ad46bb6ef...receipt is 2152 bytes and hides the parametersreceipt verifies: truenewer checkpoint extends the older: true
Size 3 is the three recorded decisions. The receipt is about 2 KB of JSON, and the order ID and amount stay hidden as commitments. receipt verifies: true means the operator’s key signed a log head that contains that row with those revealed values. The last line means no earlier row was altered between the two checkpoints.
It does not prove the log is complete. A row never written, or left out of a checkpoint, is invisible.
It does not prove you showed everyone the same log. Catching a split view needs checkpoints published where several parties read them, and someone comparing.
A hidden field is a commitment. To prove it, reveal it with its salt.
It proves the record, not that the decision was right.
The timestamp is the signer’s clock, not an independent time stamp.