Audkit
Reference

SDK reference

The Audkit client — constructor options, every method, the wrapper runtime options, and the error types.

npm install audkit
EntrypointContents
audkitThe Audkit client, error classes, the STH store interface, and every type. Also re-exports all of audkit/protocol.
audkit/nextjswithAuditLogging(), withAuditAction(), vercelRequestContext().
audkit/aiauditedTool() and its error classes.
audkit/protocolRFC 8785 canonicalization, RFC 6962 Merkle math, Ed25519 primitives — shared byte-for-byte with the platform's verifier.
npx audkitThe offline verifier CLI.

Dual ESM/CJS, side-effect free, and the only runtime dependencies are @noble/curves and @noble/hashes.

new Audkit(config)

import { Audkit } from "audkit";

const audit = new Audkit({ apiKey: process.env.AUDKIT_API_KEY! });
OptionTypeDefaultNotes
apiKeystringRequired. Throws without it.
baseUrlstringhttps://audkit.devTrailing slash is stripped.
signingKeyIdstringSee BYOK signing.
signingPrivateKeystringHex Ed25519 private key, held only by you.
sthStoreSthStoreInMemorySthStoreWhere the last verified tree head is pinned.
autoVerifybooleantrueOpportunistic consistency checking after log()/query().
autoVerifyIntervalMsnumber60_000Minimum gap between opportunistic checks.
servicePublicKeystringPin the platform's key. When omitted it is trusted on first use and pinned via the store; a later change is treated as tampering.
onTamper(error: AudkitTamperError) => voidCalled on a failed tamper check, in addition to the throw.

signingKeyId and signingPrivateKey must be provided together — the constructor throws if only one is set.

Methods

log(input)

const { id, status } = await audit.log(input);

Returns LogResult: { id: string; status: "sealed" }. Resolves only once the event has been sequenced and committed to the project's Merkle tree — see sealed before the ack. Scope: log:write.

LogInput:

FieldTypeNotes
actionstringRequired.
actorEntityRequired. { type, id, display? }.
statusEventStatussuccess (default), failed, pending, approved, denied.
targetEntity
riskEventRisklow, medium, high, critical.
context, metadataRecord<string, unknown>Arbitrary JSON.
requestId, sessionId, ipAddress, userAgentstring
agentId, model, toolName, toolCallId, approvalId, policyVersionstring
inputHash, outputHashstringCommit to a large payload without storing it.

With signing configured, log() mints the event id and blinding nonce, computes the canonical payload commitment, and attaches an Ed25519 signature — all before the request leaves the process.

query(input?)

const { events, nextCursor } = await audit.query({ action: "invoice.approved", limit: 50 });

Returns QueryResult: { events: AuditEvent[]; nextCursor?: string }. Scope: log:read.

QueryInput:

FieldTypeNotes
action, status, actorId, targetIdExact-match filters.
from, tostringTime bounds.
limitnumberDefault 50, capped at 500.
cursorstringPass back nextCursor.
entityType + entityIdstringSwitches to entity drill-down.
direction"incoming" | "outgoing" | "all"Entity mode only; default all.

Each AuditEvent carries its audit identity alongside the content: sequence, leafHash, payloadHash, payloadNonce, ciphertextHash, signingKeyId, clientSignature. After retention shredding, payloadNonce and the sensitive projections are null while leafHash survives — which is why proofs still verify for shredded events.

verify(input?)

const receipt = await audit.verify();
const controlPlane = await audit.verify({ stream: "project-audit" });

Returns a service-signed VerifyReceipt. Scope: log:verify.

exportEvents(input?)

const res = await audit.exportEvents({ format: "json", status: "failed" });

// stream it, without buffering
for await (const chunk of res.body!) { /* … */ }

// or take the whole thing
const ndjson = await res.text();

Returns the raw Response so you choose how to consume it. Accepts the same filters as query() plus format ("csv" default, or "json" for NDJSON) and max. Scope: log:export.

getRoot(stream?)

const { sth, servicePublicKey } = await audit.getRoot();

The current signed tree head. stream is "events" (default) or "project-audit". Scope: log:verify.

getInclusionProof(input)

const { leafIndex, treeSize, leafHash, proof } =
  await audit.getInclusionProof({ eventId });

Address the leaf by eventId or leafIndex; optional treeSize and stream. Returns an RFC 6962 audit path to verify locally with verifyInclusionProof from audkit/protocol. Scope: log:verify.

getConsistencyProof(input)

const { proof } = await audit.getConsistencyProof({ oldSize: 12000 });

oldSize required; optional newSize (defaults to the live size) and stream. Scope: log:verify.

checkConsistency(stream?)

const sth = await audit.checkConsistency();

Proves — with local hash arithmetic — that the server's current tree is an append-only extension of the last head this client pinned, then pins the new head and returns it. Throws AudkitTamperError when the proof fails; a network or HTTP failure throws AudkitError and pins nothing. Runs automatically, throttled, after log() and query() unless autoVerify: false. Scope: log:verify.

Pinning tree heads

import { InMemorySthStore, type SthStore, type StoredSth } from "audkit";

interface SthStore {
  load(key: string): Promise<StoredSth | null> | StoredSth | null;
  save(key: string, value: StoredSth): Promise<void> | void;
}

type StoredSth = { sth: SignedTreeHead; servicePublicKey: string };

Keys are namespaced per base URL and stream. The default InMemorySthStore protects a single process lifetime; in serverless runtimes supply a durable store, or the pin dies with the instance.

Wrapper runtime options

withAuditLogging(), withAuditAction(), and auditedTool() all accept the same transport block — every Audkit constructor option, plus:

OptionTypeNotes
client{ log(input): Promise<LogResult> }Reuse an existing client, or inject a fake in tests.
failClosedbooleanThrow audit failures instead of letting the wrapped operation continue. Default false.
onAuditError(error, input?) => void | Promise<void>Called whenever building or sending an event fails.

When no client is given, one is built from apiKey / baseUrl, falling back to AUDKIT_API_KEY, AUDKIT_BASE_URL, AUDKIT_SIGNING_KEY_ID, and AUDKIT_SIGNING_PRIVATE_KEY. Exactly one client is cached per config object, so a module-level config keeps its pinned tree head across requests.

Errors

AudkitError

Every non-2xx API response. Carries status (the HTTP status) and details (the parsed JSON error body, or the raw text). message is the server's error field when present.

import { AudkitError } from "audkit";

try {
  await audit.log(input);
} catch (error) {
  if (error instanceof AudkitError && error.status === 429) {
    // rate limited or suspended
  }
}

AudkitTamperError

Local hash arithmetic proved the server's log is not an append-only extension of history this client already saw.

PropertyType
stream"events" | "project-audit"
pinnedSthSignedTreeHead — the head this client had pinned
currentSthSignedTreeHead — the head the server just served
reasoninconsistent_tree, tree_shrunk, bad_sth_signature, service_key_changed

Raising it poisons the client: every subsequent call throws the same error until the situation is investigated.

AuditedToolMissingReasonError

From audkit/ai, when requireReason is set and no reason was supplied. Carries toolName. The failed event is written before it is thrown.

AuditedToolAuthorizationError

From audkit/ai, when authorize returned false. Carries toolName. The denied event is written before it is thrown.

audkit/protocol

The primitives, shared byte-for-byte with the platform's verifier, so a local rebuild and a server rebuild cannot silently disagree.

GroupExports
CanonicalizationcanonicalJson, normalizeJson, canonicalizePayload, toSignablePayload
CommitmentscomputePayloadHash, newPayloadNonce, isValidPayloadNonce, newEventId
Leaves & treescomputeLeafHash, encodeLeaf, merkleRoot, merkleLeafHash, merkleNodeHash, emptyTreeRoot, CompactMerkleTree
ProofsinclusionProof, consistencyProof, verifyInclusionProof, verifyConsistencyProof
SigninggenerateSigningKeyPair, publicKeyFromPrivate, isValidPublicKey, signPayloadHash, verifyPayloadSignature, signTreeHead, verifyTreeHead
ConstantsLEAF_VERSION, TREE_HEAD_VERSION, SIGNING_ALGORITHM, SIGNING_PROTOCOL_VERSION

On this page