API Reference
Receipts
Section titled “Receipts”import { createReceipt, signReceipt, verifyReceipt, generateKeyPair, hashReceipt, verifyChain,} from "@obsigna/sdk-ts";Functions
Section titled “Functions”createReceipt
Section titled “createReceipt”function createReceipt(input: CreateReceiptInput): UnsignedAgentReceiptBuild an unsigned receipt. Auto-generates an ID (urn:uuid:...), action ID, issuance date, and action timestamp.
signReceipt
Section titled “signReceipt”function signReceipt( unsigned: UnsignedAgentReceipt, privateKey: string, verificationMethod: string,): AgentReceiptSign an unsigned receipt with an Ed25519 private key (PEM-encoded). Returns a signed AgentReceipt with an Ed25519Signature2020 proof.
verifyReceipt
Section titled “verifyReceipt”function verifyReceipt(receipt: AgentReceipt, publicKey: string): booleanVerify the Ed25519 signature on a signed receipt.
generateKeyPair
Section titled “generateKeyPair”function generateKeyPair(): KeyPairGenerate an Ed25519 key pair in PEM format.
hashReceipt
Section titled “hashReceipt”function hashReceipt(receipt: AgentReceipt): stringCompute the SHA-256 hash of a receipt (excluding proof) using canonical JSON. Returns sha256:<hex>.
verifyChain
Section titled “verifyChain”function verifyChain(receipts: AgentReceipt[], publicKey: string): ChainVerificationVerify an entire receipt chain: signatures, hash linkage, and sequence numbers.
canonicalize
Section titled “canonicalize”function canonicalize(value: unknown): stringRFC 8785 canonical JSON serialization.
sha256
Section titled “sha256”function sha256(data: string): stringCompute a SHA-256 hash, returned as hex.
CreateReceiptInput
Section titled “CreateReceiptInput”interface CreateReceiptInput { issuer: Issuer; principal: Principal; action: Omit<Action, "id" | "timestamp">; outcome: Outcome; chain: Chain; intent?: Intent; authorization?: Authorization; actionTimestamp?: string;}AgentReceipt
Section titled “AgentReceipt”interface AgentReceipt { "@context": readonly string[]; id: string; type: readonly string[]; version: string; issuer: Issuer; issuanceDate: string; credentialSubject: CredentialSubject; proof: Proof;}
type UnsignedAgentReceipt = Omit<AgentReceipt, "proof">KeyPair
Section titled “KeyPair”interface KeyPair { publicKey: string; privateKey: string;}Issuer
Section titled “Issuer”interface Issuer { id: string; type?: string; name?: string; operator?: Operator; model?: string; session_id?: string; runtime?: Runtime; // open metadata container (v0.5.0, ADR-0026)}
// Open container for runtime/observability metadata. The index signature keeps// it extensible, so unknown runtime keys survive round-trips.interface Runtime { agent_id?: string; // the sub-agent that issued the receipt agent_type?: string; // e.g. "general-purpose" [key: string]: unknown;}
interface Operator { id: string; name: string;}Principal
Section titled “Principal”interface Principal { id: string; type?: string;}Action
Section titled “Action”interface Action { id: string; type: string; risk_level: RiskLevel; target?: ActionTarget; parameters_hash?: string; timestamp: string; trusted_timestamp?: string | null;}
interface ActionTarget { system: string; resource?: string;}Outcome
Section titled “Outcome”interface Outcome { status: OutcomeStatus; error?: string | null; reversible?: boolean; reversal_method?: string; reversal_window_seconds?: number; state_change?: StateChange;}
interface StateChange { before_hash: string; after_hash: string;}interface Chain { sequence: number; previous_receipt_hash: string | null; chain_id: string;}ChainVerification
Section titled “ChainVerification”type ChainVerification = { valid: boolean; length: number; receipts: ReceiptVerification[]; brokenAt: number;}
type ReceiptVerification = { index: number; receiptId: string; signatureValid: boolean; hashLinkValid: boolean; sequenceValid: boolean;}Intent / Authorization / Proof
Section titled “Intent / Authorization / Proof”interface Intent { conversation_hash?: string; prompt_preview?: string; prompt_preview_truncated?: boolean; reasoning_hash?: string;}
interface Authorization { scopes: string[]; granted_at: string; expires_at?: string; grant_ref?: string | null;}
interface Proof { type: string; created?: string; verificationMethod?: string; proofPurpose?: string; proofValue: string;}Constants
Section titled “Constants”type RiskLevel = "low" | "medium" | "high" | "critical"type OutcomeStatus = "success" | "failure" | "pending"
const CONTEXT: readonly ["https://www.w3.org/ns/credentials/v2", "https://agentreceipts.ai/context/v2"]const CREDENTIAL_TYPE: readonly ["VerifiableCredential", "AgentReceipt"]const RECEIPT_VERSION: "0.5.0" // receipt schemaconst VERSION: "0.9.0" // package versionParameter disclosure (HPKE)
Section titled “Parameter disclosure (HPKE)”import { generateForensicKeyPair, encryptDisclosure, decryptDisclosure, type ForensicKeyPair, type DisclosureEnvelope, type DisclosureRecipient,} from "@obsigna/sdk-ts";HPKE-based envelope for encrypting tool-call parameters into a receipt’s
parameters_disclosure field (ADR-0012, ciphersuite
hpke-x25519-hkdf-sha256-aes-256-gcm). The emitter holds only the forensic
public key and never sees the plaintext again after encryption; the private key
stays offline. For the threat model and operator configuration see the
Parameter Disclosure specification.
For the envelope JSON shape see the schema reference.
This is the SDK-direct path. When emitting through the daemon the operator provides the public key in daemon config; the daemon calls these helpers automatically.
All three functions are async (they use node:crypto internally).
Functions
Section titled “Functions”generateForensicKeyPair
Section titled “generateForensicKeyPair”async function generateForensicKeyPair(): Promise<ForensicKeyPair>Generate an X25519 key pair for forensic disclosure. publicKey (32-byte
Uint8Array) is shared with emitters. privateKey (32-byte Uint8Array) must
be kept offline, separate from the Ed25519 signing key (ADR-0001 / ADR-0012).
encryptDisclosure
Section titled “encryptDisclosure”async function encryptDisclosure( params: Record<string, unknown>, recipientPublicKey: Uint8Array, kid: string,): Promise<DisclosureEnvelope>Encrypt params as a v1 HPKE disclosure envelope. params is RFC 8785
JCS-canonicalized before encryption so all SDKs produce the same ciphertext for
the same parameters object. params must be a plain object (not null or an
array). recipientPublicKey must be 32 bytes. kid is the recipient key
identifier (sha256:<hex> fingerprint or did:key DID URL). Throws on invalid
arguments.
decryptDisclosure
Section titled “decryptDisclosure”async function decryptDisclosure( env: DisclosureEnvelope, recipientPrivateKey: Uint8Array,): Promise<Record<string, unknown>>Recover the plaintext parameters from a v1 HPKE disclosure envelope.
recipientPrivateKey must be 32 bytes. Throws if the envelope version or
algorithm is unsupported, if the key or ciphertext is malformed, or if AEAD
authentication fails.
Usage example
Section titled “Usage example”// Key management (run once offline, store private key securely)const kp = await generateForensicKeyPair();// Share kp.publicKey with emitters; keep kp.privateKey offline.// Compute the fingerprint manually: sha256(kp.publicKey) → "sha256:..."
// Emitter side (holds only the public key)const env = await encryptDisclosure( { path: "/etc/passwd", mode: "r" }, kp.publicKey, "sha256:...",);// embed env in action.parameters_disclosure, then sign the receipt
// Forensic / audit side (holds the offline private key)const params = await decryptDisclosure(env, kp.privateKey);// params == { mode: "r", path: "/etc/passwd" }Recovering a stored disclosure
Section titled “Recovering a stored disclosure”In practice the envelope comes from a stored receipt and the private key from
the file obsigna-daemon --init-forensic-key wrote — a raw 32-byte X25519
key, not PEM, so read it as bytes and pass it straight in. Pull the envelope out
of the receipt JSON at credentialSubject.action.parameters_disclosure:
import { readFileSync } from "node:fs";import { decryptDisclosure } from "@obsigna/sdk-ts";
// raw 32-byte private key written by --init-forensic-key (kept offline)const priv = new Uint8Array(readFileSync("/path/to/forensic.key"));
// from: obsigna receipt show <seq> --json > receipt.jsonconst receipt = JSON.parse(readFileSync("receipt.json", "utf8"));const env = receipt.credentialSubject.action.parameters_disclosure;
const params = await decryptDisclosure(env, priv);// params holds the original tool-call parametersForensicKeyPair
Section titled “ForensicKeyPair”interface ForensicKeyPair { /** 32-byte X25519 public key. Share with emitters to enable encryption. */ publicKey: Uint8Array; /** 32-byte X25519 private key. Keep offline; required to decrypt. */ privateKey: Uint8Array;}DisclosureEnvelope / DisclosureRecipient
Section titled “DisclosureEnvelope / DisclosureRecipient”interface DisclosureEnvelope { v: "1"; alg: "hpke-x25519-hkdf-sha256-aes-256-gcm"; recipients: [DisclosureRecipient]; // length-1 tuple; v1 single-recipient ct: string; // AEAD ciphertext; unpadded base64url}
interface DisclosureRecipient { kid: string; enc: string; // HPKE encapsulated key; unpadded base64url, 43 chars for X25519}v1 HPKE envelope stored in action.parameters_disclosure. Field names follow
RFC 9180 §4.1 (enc, not encap).
Note: ForensicKeyFingerprint and ForensicPublicFromPrivate are available
in the Go SDK only (added in PR #722). Use sha256(kp.publicKey) from the
existing sha256 export to compute the fingerprint string in TypeScript.
import { ReceiptStore, openStore, verifyStoredChain } from "@obsigna/sdk-ts";SQLite-backed receipt persistence and querying.
openStore
Section titled “openStore”function openStore(dbPath: string): ReceiptStoreOpen or create a SQLite receipt store. Pass ":memory:" for an in-memory store.
verifyStoredChain
Section titled “verifyStoredChain”function verifyStoredChain( store: ReceiptStore, chainId: string, publicKey: string,): ChainVerificationLoad a chain from the store and verify its integrity.
ReceiptStore
Section titled “ReceiptStore”Use openStore(dbPath) to create a store — the class constructor is an implementation detail. openStore is the stable public factory.
class ReceiptStore { constructor(dbPath: string); insert(receipt: AgentReceipt, receiptHash: string): void; getById(id: string): AgentReceipt | undefined; getChain(chainId: string): AgentReceipt[]; query(filters: ReceiptQuery): AgentReceipt[]; stats(): StoreStats; close(): void;}ReceiptQuery
Section titled “ReceiptQuery”interface ReceiptQuery { chainId?: string; actionType?: string; riskLevel?: RiskLevel; status?: OutcomeStatus; after?: string; before?: string; /** When omitted, all matching rows are returned (no default cap). */ limit?: number; /** * Sort order. Default `"asc"` (oldest first). Use `"desc"` for newest first; * ties on timestamp are broken by sequence descending. */ order?: "asc" | "desc";}StoreStats
Section titled “StoreStats”interface StoreStats { total: number; chains: number; byRisk: { risk_level: string; count: number }[]; byStatus: { status: string; count: number }[]; byAction: { action_type: string; count: number }[];}Taxonomy
Section titled “Taxonomy”import { classifyToolCall, getActionType, resolveActionType, loadTaxonomyConfig, ALL_ACTIONS,} from "@obsigna/sdk-ts";Action type registry and tool call classification.
classifyToolCall
Section titled “classifyToolCall”function classifyToolCall( toolName: string, mappings?: TaxonomyMapping[],): ClassificationResultClassify a tool call to an action type and risk level using the provided mappings.
getActionType
Section titled “getActionType”function getActionType(type: string): ActionTypeEntry | undefinedLook up an action type by name. Returns undefined if not found.
resolveActionType
Section titled “resolveActionType”function resolveActionType(type: string): ActionTypeEntryLike getActionType but returns an “unknown” fallback instead of undefined.
loadTaxonomyConfig
Section titled “loadTaxonomyConfig”function loadTaxonomyConfig(filePath: string): TaxonomyMapping[]Load taxonomy mappings from a JSON file.
interface ActionTypeEntry { type: string; description: string; risk_level: RiskLevel;}
interface TaxonomyMapping { tool_name: string; action_type: string;}
interface ClassificationResult { action_type: string; risk_level: RiskLevel;}Built-in action registries
Section titled “Built-in action registries”const FILESYSTEM_ACTIONS: readonly ActionTypeEntry[] // 7 typesconst SYSTEM_ACTIONS: readonly ActionTypeEntry[] // 7 typesconst ALL_ACTIONS: readonly ActionTypeEntry[] // all + unknownconst UNKNOWN_ACTION: ActionTypeEntryDATA_ACTIONS (3 data/API types) is exported from the taxonomy subpath, not the package root:
import { DATA_ACTIONS } from "@obsigna/sdk-ts/taxonomy";