Payload privacy
Send a keyed digest of your prompt rather than the prompt. Commitments, no-payload mode, and what a counterparty can still verify without seeing your content.
Payload Privacy
Your prompts and model outputs never have to reach Vorim. The audit event carries a digest of them, computed in your process. This section is about making that a guarantee rather than a habit, and about the difference between a digest and a commitment.
Commit, don’t just hash
A bare SHA-256 of a prompt is not a commitment, it is a lookup key. Prompts are low-entropy and usually templated, so anyone holding the digest and the template recovers the content by trying candidates until a hash matches. That includes us, and anyone who obtains an export.
Use a keyed commitment for anything a person or a model wrote. The key stays in your process and is never sent. Keep hashPayload only for content that is already high-entropy, such as a file digest or a random identifier.
import { commitPayload, hashPayload } from '@vorim/sdk';
// The key lives in your secret store and is never sent to Vorim.
const key = process.env.VORIM_COMMITMENT_KEY!;
await vorim.emit({
agent_id: agent.agent_id,
event_type: 'tool_call',
action: 'invoice.refund',
result: 'success',
input_hash: await commitPayload(prompt, key), // hmac-sha256:...
output_hash: await commitPayload(completion, key),
});typescriptDisclose later, to whoever needs it
To prove that a specific prompt produced a specific audit record, hand the verifier the content and the key. They recompute and compare. Until then the record shows that an action happened and nothing about what was in it.
import { commitPayload } from '@vorim/sdk';
// The auditor has the event, the prompt, and the key. They recompute.
const recomputed = await commitPayload(disclosedPrompt, disclosedKey);
console.log(recomputed === event.input_hash); // truetypescriptRefuse to send content at all
The hash fields were always the right place for content, but nothing enforced it, and metadata is a free-form object that a whole prompt fits into by accident. Turn the guard on and the SDK throws before anything leaves your process.
It rejects non-scalar metadata, metadata strings over the limit (256 characters by default), and any hash field that is not a well-formed digest, which is what catches a raw prompt passed to input_hash.
const vorim = createVorim({
apiKey: process.env.VORIM_API_KEY!,
noPayload: true, // or { maxMetadataChars: 1024 }
});
await vorim.emit({
agent_id: agent.agent_id,
event_type: 'tool_call',
action: 'invoice.refund',
result: 'success',
metadata: { tool: 'stripe.refunds.create', attempt: 2 }, // ok
});
await vorim.emit({
agent_id: agent.agent_id,
event_type: 'tool_call',
action: 'invoice.refund',
result: 'success',
metadata: { prompt: fullPrompt }, // throws
});
// VorimError PAYLOAD_BLOCKED — nothing was senttypescriptReferencing an event
Every emit returns a stable content digest alongside the event id. The digest is computed over exactly the bytes the signature covers, so you can recompute it yourself and get the same value, and hand it to a downstream evidence layer as a reference that does not depend on trusting either of us to compute it.
const { events } = await vorim.emit({ /* ... */ });
// events: [{ event_id: 'evt_...', digest: 'sha256:...' }]
// Recompute it yourself, offline, from the event you sent.
import { eventDigest } from '@vorim/sdk';
console.log(await eventDigest(sentEvent) === events[0].digest); // truetypescriptThe same value is what prev_event_hash references on the next event, so a hash-chained emitter is already producing these. It is a content digest rather than an identity: two byte-identical events share one, which is why the response carries the event id beside it.
Book a demo for a walkthrough, or contact us for support. For enterprise needs, reach out at sales@vorim.ai.