Every app has an audit log. Almost none of them can actually prove anything.
A typical audit log is a table in a database you control, with timestamps from a clock you can set. It's fine until someone has a reason to doubt it: an auditor, a customer, opposing counsel. At that point, "here's our log" means "trust our database," which is exactly what an audit is supposed to avoid.
A trustworthy audit log needs three properties your database does not give you for free:
- Integrity. Each entry is provably unchanged since it was written.
- Completeness. A missing or reordered entry is detectable from the data itself.
- Portability. Anyone can verify it without access to your systems and without trusting you.
Here's how to get all three with the Invoance SDK, then stream the log to your SIEM and hand it to an auditor. Examples are in Node.js; the same API exists in Python, Go, Rust, Java, Ruby, .NET, and PHP.
1. Register the org you're logging for
Audit events belong to an organization (your tenant, or an end customer). Register it once:
import { InvoanceClient } from "invoance";
const client = new InvoanceClient(); // reads INVOANCE_API_KEY
await client.audit.orgs.create({
organizationId: "org_acme",
name: "Acme Inc.",
});
2. Append a signed event
Instead of an INSERT, you append. Invoance canonicalizes the event, signs it with your tenant's own key, and writes it to an append-only ledger with a gapless sequence number:
const event = await client.audit.events.ingest({
organizationId: "org_acme",
action: "user.role.granted",
actor: { type: "user", id: "u_42", name: "Ada Lovelace" },
targets: [{ type: "user", id: "u_99" }],
metadata: { role: "admin", ip: "203.0.113.7" },
});
const eventId = event.event_id as string;
The gapless sequence is what makes a missing record detectable later. There's no delete and no update, so tampering means breaking either a signature or the chain.
3. Verify it, without trusting the vendor
This is the part your database can't do. The SDK ships the same verification the backend uses, so you can recompute an event's canonical hash and check its signature entirely client-side:
import { verifyAuditEvent } from "invoance";
const record = await client.audit.events.get(eventId);
const result = verifyAuditEvent(record);
console.log(result.valid); // true if the signature and hash check out
console.log(result.payloadHash); // the recomputed hash
An auditor can run the exact same check against the tenant's published public key, with no account and no access to your systems.
4. Query and export for the auditor
When someone asks for the trail, you hand over something that verifies itself:
const page = await client.audit.events.list({
organizationId: "org_acme",
actions: "user.role.granted",
rangeStart: "2026-01-01T00:00:00Z",
});
// Or queue a packaged export (CSV or NDJSON)
await client.audit.exports.create({
organizationId: "org_acme",
format: "csv",
});
Every record in that export carries its own signature, so the file is proof on its own, not a CSV anyone has to trust.
5. Stream it to your SIEM
Provable logs are more useful when they show up where your security team already works. Create a webhook stream and Invoance pushes every new signed event to it. The signing secret is returned once, so you can verify deliveries yourself:
const stream = await client.audit.streams.create("org_acme", {
type: "webhook",
url: "https://siem.acme.com/hooks/invoance",
});
// stream.signing_secret -> store it now; it's shown only once
6. Give your customers a hosted viewer
When an end customer or their auditor wants to see the log directly, you don't have to build a UI. Mint a one-time, read-only hosted-viewer link scoped to their org:
const portal = await client.audit.portalSessions.create({
organizationId: "org_acme",
intent: "audit_logs",
});
// portal.url -> a self-serve, verifiable view of that org's audit log
They browse and verify their own trail. You never expose your systems, and they never need an Invoance account.
Try it
The audit-log API (plus events, documents, AI attestations, and traces) is available in official SDKs for 8 languages.
- 📚 Docs and quickstarts: invoance.com/developers
- 💻 Source: github.com/Invoance
npm install invoance
pip install invoance
cargo add invoance
Build the audit log you'd be comfortable handing to an auditor.
Top comments (0)