SDK reference
The Audkit client — constructor options, every method, the wrapper runtime options, and the error types.
npm install audkit| Entrypoint | Contents |
|---|---|
audkit | The Audkit client, error classes, the STH store interface, and every type. Also re-exports all of audkit/protocol. |
audkit/nextjs | withAuditLogging(), withAuditAction(), vercelRequestContext(). |
audkit/ai | auditedTool() and its error classes. |
audkit/protocol | RFC 8785 canonicalization, RFC 6962 Merkle math, Ed25519 primitives — shared byte-for-byte with the platform's verifier. |
npx audkit | The 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! });| Option | Type | Default | Notes |
|---|---|---|---|
apiKey | string | — | Required. Throws without it. |
baseUrl | string | https://audkit.dev | Trailing slash is stripped. |
signingKeyId | string | — | See BYOK signing. |
signingPrivateKey | string | — | Hex Ed25519 private key, held only by you. |
sthStore | SthStore | InMemorySthStore | Where the last verified tree head is pinned. |
autoVerify | boolean | true | Opportunistic consistency checking after log()/query(). |
autoVerifyIntervalMs | number | 60_000 | Minimum gap between opportunistic checks. |
servicePublicKey | string | — | Pin 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) => void | — | Called 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:
| Field | Type | Notes |
|---|---|---|
action | string | Required. |
actor | Entity | Required. { type, id, display? }. |
status | EventStatus | success (default), failed, pending, approved, denied. |
target | Entity | |
risk | EventRisk | low, medium, high, critical. |
context, metadata | Record<string, unknown> | Arbitrary JSON. |
requestId, sessionId, ipAddress, userAgent | string | |
agentId, model, toolName, toolCallId, approvalId, policyVersion | string | |
inputHash, outputHash | string | Commit 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:
| Field | Type | Notes |
|---|---|---|
action, status, actorId, targetId | Exact-match filters. | |
from, to | string | Time bounds. |
limit | number | Default 50, capped at 500. |
cursor | string | Pass back nextCursor. |
entityType + entityId | string | Switches 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:
| Option | Type | Notes |
|---|---|---|
client | { log(input): Promise<LogResult> } | Reuse an existing client, or inject a fake in tests. |
failClosed | boolean | Throw 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.
| Property | Type |
|---|---|
stream | "events" | "project-audit" |
pinnedSth | SignedTreeHead — the head this client had pinned |
currentSth | SignedTreeHead — the head the server just served |
reason | inconsistent_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.
| Group | Exports |
|---|---|
| Canonicalization | canonicalJson, normalizeJson, canonicalizePayload, toSignablePayload |
| Commitments | computePayloadHash, newPayloadNonce, isValidPayloadNonce, newEventId |
| Leaves & trees | computeLeafHash, encodeLeaf, merkleRoot, merkleLeafHash, merkleNodeHash, emptyTreeRoot, CompactMerkleTree |
| Proofs | inclusionProof, consistencyProof, verifyInclusionProof, verifyConsistencyProof |
| Signing | generateSigningKeyPair, publicKeyFromPrivate, isValidPublicKey, signPayloadHash, verifyPayloadSignature, signTreeHead, verifyTreeHead |
| Constants | LEAF_VERSION, TREE_HEAD_VERSION, SIGNING_ALGORITHM, SIGNING_PROTOCOL_VERSION |
Related
- REST API — the endpoints every method above calls.
- Verification — how to use the proofs and receipts.
- Next.js and AI agent tools — the wrappers.