Home
Home/Developers/SDKs/node
Ed25519 signaturesSHA-256 hashes8 SDKs
Status
Sign inStart free
Home
Start here
Overview
Authentication
Errors
FAQ
API
Events
Canonical JSON and hashes
Documents
Anchoring a file
AI attestations
Attestation schema
Verifying attestations
Traces
Sealing a trace
Audit logs
Organizations
Streams
Portal
Public proof
Event schema
Exporting events
Integrations
Clerk
Auth0
Embeddable viewer
All endpoints
Reference
SDKs
Node.js
Python
Go
Java
Ruby
Rust
.NET
PHP
REST
Verification
Docs · SDKs

Node.js SDK

Install the Node.js SDK, build a client, see every method with a Node.js sample, and verify records offline.

sha-256 · 3a352297…2592
sha-256 · 971e439d…e24c
RESTNode.jsPythonGoJavaRubyRust.NETPHP
Install

Node.js

invoance on npm.

Node 18 or later. No runtime dependencies; Ed25519 checks use node:crypto.

Terminal
npm install invoance
Client
apiKeyThe API key. Falls back to INVOANCE_API_KEY; the client throws when neither is set.
baseUrlAPI host. Falls back to INVOANCE_BASE_URL, then https://api.invoance.com. Trailing slashes are removed.
apiVersionPath prefix put before every request path. Default v1.
timeoutMsPer-request timeout in milliseconds. Default 30000; past it the call throws TimeoutError.
idempotencyKeyDefault Idempotency-Key header for every mutating request; a per-call key wins.
extraHeadersHeaders merged into every request.
RetriesNone. Each request is sent once; on TimeoutError or NetworkError, retry it yourself with the same Idempotency-Key.
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY and INVOANCE_BASE_URL from the environment.
const client = new InvoanceClient();

// Or pass options.
const configured = new InvoanceClient({
  apiKey: "invoance_live_...",
  baseUrl: "https://api.invoance.com",
  timeoutMs: 60_000,
});

// GET /v1/me checks no scope, so any live key passes. Never throws.
const { valid, reason } = await client.validate();
console.log(valid, reason);
Methods

Every endpoint with a Node.js sample, by resource. Open a row for the sample; the link opens the endpoint card with its fields, response and errors.

EventsReference
POST/v1/eventsIngest an event
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.events.ingest({
  eventType: "policy.approval",
  eventTime: "2026-09-22T08:14:07Z",
  payload: {
    policy_id: "pol_8472",
    approved_by: "risk_committee",
    decision: "approved",
  },
  idempotencyKey: "policy-approval-pol_8472",
});
console.log(result.event_id, result.ingested_at);
Ingest an event: fields, response and errors
GET/v1/eventsList events
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const page = await client.events.list({
  page: 1,
  limit: 50,
  eventType: "policy.approval",
});
console.log(page.total, page.has_more);
for (const event of page.events) {
  console.log(event.event_id, event.ingested_at, event.payload_hash);
}
List events: fields, response and errors
GET/v1/events/{event_id}Get an event
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const event = await client.events.get("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
console.log(event.event_type, event.ingested_at);
console.log(event.payload_hash, event.event_hash, event.request_hash);
console.log(event.payload);
Get an event: fields, response and errors
POST/v1/events/{event_id}/verifyVerify an event
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.events.verify("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4", {
  payload: {
    policy_id: "pol_8472",
    approved_by: "risk_committee",
    decision: "approved",
  },
});
console.log(result.match_result, result.matched_field);
console.log(result.anchored_hash, result.submitted_hash, result.anchored_at);
Verify an event: fields, response and errors
DocumentsReference
POST/v1/document/anchorAnchor a document
Node.js
import { readFileSync } from "node:fs";
import { createHash } from "node:crypto";
import { InvoanceClient } from "invoance";

const file = readFileSync("./INV-2026-0917.pdf");
const documentHash = createHash("sha256").update(file).digest("hex");

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.documents.anchor({
  documentHash,
  documentRef: "INV-2026-0917.pdf",
  eventType: "invoice.issued",
  metadata: { invoice_number: "INV-2026-0917", amount: 5230, currency: "USD" },
  idempotencyKey: "anchor-" + documentHash,
});
console.log(result.event_id, result.status);
Anchor a document: fields, response and errors
GET/v1/documentList documents
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const page = await client.documents.list({
  limit: 25,
  dateFrom: "2026-09-01T00:00:00Z",
});
console.log(page.total, page.has_more);
for (const d of page.documents) {
  console.log(d.event_id, d.document_ref, d.has_original);
}
List documents: fields, response and errors
GET/v1/document/{event_id}Get a document
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const doc = await client.documents.get("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
console.log(doc.document_hash, doc.has_original, doc.created_at);
console.log(doc.organization?.issuer_name, doc.organization?.domain_verified);
Get a document: fields, response and errors
GET/v1/document/{event_id}/originalDownload the original
Node.js
import { writeFileSync } from "node:fs";
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const bytes = await client.documents.getOriginal("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
writeFileSync("./INV-2026-0917.pdf", Buffer.from(bytes));
console.log(bytes.byteLength);
Download the original: fields, response and errors
POST/v1/document/{event_id}/verifyVerify a document hash
Node.js
import { readFileSync } from "node:fs";
import { createHash } from "node:crypto";
import { InvoanceClient } from "invoance";

const file = readFileSync("./INV-2026-0917.pdf");
const documentHash = createHash("sha256").update(file).digest("hex");

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.documents.verify("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4", {
  documentHash,
});
console.log(result.match_result, result.anchored_hash, result.anchored_at);
Verify a document hash: fields, response and errors
AI AttestationsReference
POST/v1/ai/attestationsIngest an attestation
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.attestations.ingest({
  type: "output",
  input: "Summarize the termination clause in contract CT-8472.",
  output: "Either party may terminate with 30 days written notice. Early termination fees do not apply after month 12.",
  modelProvider: "openai",
  modelName: "gpt-4.1",
  modelVersion: "2026-04-14",
  subject: { userId: "u_4821", sessionId: "sess_9f3a", department: "legal" },
  idempotencyKey: "ct-8472-summary-1",
});
console.log(result.attestation_id, result.payload_hash);
Ingest an attestation: fields, response and errors
GET/v1/ai/attestationsList attestations
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const page = await client.attestations.list({
  limit: 50,
  attestationType: "output",
  modelProvider: "openai",
});
console.log(page.total, page.has_more, page.attestations.length);
List attestations: fields, response and errors
GET/v1/ai/attestations/{attestation_id}Get an attestation
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const att = await client.attestations.get("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
console.log(att.attestation_hash, att.signature_alg, att.public_key);
Get an attestation: fields, response and errors
GET/v1/ai/attestations/{attestation_id}/rawGet the raw payload
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const raw = await client.attestations.getRaw("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
console.log(raw.type, raw.context);
Get the raw payload: fields, response and errors
POST/v1/ai/attestations/{attestation_id}/verifyVerify a hash
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.attestations.verify("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4", {
  contentHash: "c4efe15781214a84046ad7e0592977c634a5cf45f4c1e06160daf760a295a8df",
});
console.log(result.match_result, result.matched_field);
Verify a hash: fields, response and errors
TracesReference
POST/v1/tracesCreate a trace
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const trace = await client.traces.create({
  label: "Invoice batch 2026-09",
  metadata: { batch_id: "b_4471", region: "eu-west" },
});
console.log(trace.trace_id, trace.status);
Create a trace: fields, response and errors
GET/v1/tracesList traces
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const page = await client.traces.list({ status: "open", page: 1, limit: 25 });
for (const trace of page.traces) {
  console.log(trace.trace_id, trace.label, trace.status);
}
console.log(page.total, page.has_more);
List traces: fields, response and errors
GET/v1/traces/{trace_id}Get a trace
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const trace = await client.traces.get("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4", {
  event_page: 1,
  event_limit: 50,
});
console.log(trace.status, trace.composite_hash);
for (const event of trace.events) {
  console.log(event.event_id, event.event_type, event.payload_hash);
}
Get a trace: fields, response and errors
DELETE/v1/traces/{trace_id}Delete an empty trace
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.traces.delete("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
console.log(result.trace_id, result.deleted);
Delete an empty trace: fields, response and errors
POST/v1/traces/{trace_id}/sealSeal a trace
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const traceId = "7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4";

const seal = await client.traces.seal(traceId);
console.log(seal.status); // "sealing"

// The seal runs in the background. Poll until the status changes.
let trace = await client.traces.get(traceId);
while (trace.status === "sealing") {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  trace = await client.traces.get(traceId);
}
console.log(trace.status, trace.composite_hash);
Seal a trace: fields, response and errors
GET/v1/traces/{trace_id}/proofGet the proof bundle
Node.js
import { createHash } from "node:crypto";
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const bundle = await client.traces.proof("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");

// The SDK's TraceProofBundle type declares events and seal_event only; the
// JSON also carries documents and attestations, so read them off the raw object.
const raw = bundle as unknown as {
  events: { timestamp: string; content_hash: string }[];
  documents: { timestamp: string; document_hash: string }[];
  attestations: { timestamp: string; payload_hash: string }[];
};

// Recompute the composite hash: SHA-256 over the raw item hashes in
// timestamp order across events, documents and attestations.
const items = [
  ...raw.events.map((e) => ({ at: e.timestamp, hash: e.content_hash })),
  ...raw.documents.map((d) => ({ at: d.timestamp, hash: d.document_hash })),
  ...raw.attestations.map((a) => ({ at: a.timestamp, hash: a.payload_hash })),
].sort((a, b) => a.at.localeCompare(b.at));

const hasher = createHash("sha256");
for (const item of items) hasher.update(Buffer.from(item.hash, "hex"));
const recomputed = hasher.digest("hex");

console.log(bundle.composite_hash);
console.log(recomputed === bundle.composite_hash ? "composite hash matches" : "mismatch");
Get the proof bundle: fields, response and errors
GET/v1/traces/{trace_id}/proof/pdfDownload the proof bundle as PDF
Node.js
import { writeFileSync } from "node:fs";
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const pdf = await client.traces.proofPdf("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
writeFileSync("trace-proof.pdf", Buffer.from(pdf));
console.log("wrote trace-proof.pdf", pdf.byteLength, "bytes");
Download the proof bundle as PDF: fields, response and errors
GET/v1/proof/trace/{trace_id}Get the public proof
Node.js
// No API key: the public proof endpoint is unauthenticated.
const traceId = "7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4";

const res = await fetch("https://api.invoance.com/v1/proof/trace/" + traceId);
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const proof = await res.json();
console.log(proof.issuer_name, proof.composite_hash);
console.log(proof.events.length, "events", proof.documents.length, "documents", proof.attestations.length, "attestations");
Get the public proof: fields, response and errors
Audit LogsReference
POST/v1/audit/eventsIngest an audit event
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.audit.events.ingest({
  organizationId: "org_8472",
  action: "user.signed_in",
  occurredAt: "2026-09-22T08:14:07Z",
  actor: { type: "user", id: "u_4821", name: "Ada Lovelace" },
  targets: [{ type: "workspace", id: "ws_17" }],
  context: { location: "203.0.113.10", user_agent: "Mozilla/5.0" },
  metadata: { method: "sso", mfa: true },
  idempotencyKey: "signin-u_4821-2026-09-22T08:14:07Z",
});
console.log(result.event_id, result.ingested_at);
Ingest an audit event: fields, response and errors
GET/v1/audit/eventsList audit events
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const page = await client.audit.events.list({
  organizationId: "org_8472",
  actions: "user.signed_in,user.signed_out",
  rangeStart: "2026-09-01T00:00:00Z",
  limit: 50,
});
for (const event of page.events) {
  console.log(event.seq, event.action, event.actor?.id);
}
console.log(page.next_cursor);
List audit events: fields, response and errors
GET/v1/audit/events/{id}Get an audit event
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const event = await client.audit.events.get("aevt_01J0Y1Z2A3B4C5D6E7F8G9H0JK");
console.log(event.seq, event.action, event.payload_hash);
Get an audit event: fields, response and errors
GET/v1/audit/events/{id}/verifyVerify an audit event
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.audit.events.verify("aevt_01J0Y1Z2A3B4C5D6E7F8G9H0JK");
console.log(result.valid, result.reason, result.payload_hash);
Verify an audit event: fields, response and errors
POST/v1/audit/orgsCreate an audit org
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const org = await client.audit.orgs.create({
  organizationId: "org_8472",
  name: "Acme Robotics",
});
console.log(org.id, org.retention_days);
Create an audit org: fields, response and errors
GET/v1/audit/orgsList audit orgs
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.audit.orgs.list({ includeArchived: true });
for (const org of result.orgs as Array<Record<string, unknown>>) {
  console.log(org.id, org.organization_id, org.archived_at);
}
List audit orgs: fields, response and errors
PATCH/v1/audit/orgs/{id}Rename an audit org
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const org = await client.audit.orgs.update("org_8472", { name: "Acme Robotics Ltd" });
console.log(org.name);

// Pass null to clear the name.
await client.audit.orgs.update("org_8472", { name: null });
Rename an audit org: fields, response and errors
DELETE/v1/audit/orgs/{id}Delete an audit org
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.audit.orgs.delete("org_8472");
console.log(result.deleted, result.id);
Delete an audit org: fields, response and errors
POST/v1/audit/orgs/{id}/archiveArchive an audit org
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const org = await client.audit.orgs.archive("org_8472");
console.log(org.archived_at);
Archive an audit org: fields, response and errors
POST/v1/audit/orgs/{id}/unarchiveUnarchive an audit org
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const org = await client.audit.orgs.unarchive("org_8472");
console.log(org.archived_at);
Unarchive an audit org: fields, response and errors
GET/v1/audit/orgs/{id}/integrityCheck an org's sequence integrity
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const report = await client.audit.orgs.integrity("org_8472");
console.log(report.contiguous, report.count, report.expected, report.gaps);
Check an org's sequence integrity: fields, response and errors
PUT/v1/audit/orgs/{id}/retentionSet an org's retention
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.audit.orgs.setRetention("org_8472", 365);
console.log(result.retention_days, result.clamped, result.plan_cap_days);
Set an org's retention: fields, response and errors
POST/v1/audit/orgs/{id}/streamsCreate a webhook stream
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const stream = await client.audit.streams.create("org_8472", {
  url: "https://siem.example.com/hooks/invoance",
});
// Store signing_secret now; it is not returned again.
console.log(stream.id, stream.signing_secret);
Create a webhook stream: fields, response and errors
GET/v1/audit/orgs/{id}/streamsList an org's streams
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.audit.streams.list("org_8472");
for (const stream of result.streams as Array<Record<string, unknown>>) {
  console.log(stream.id, stream.state, stream.cursor_seq, stream.last_error);
}
List an org's streams: fields, response and errors
DELETE/v1/audit/orgs/{id}/streams/{stream_id}Delete a stream
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.audit.streams.delete("org_8472", "astr_01J0Y3N5P7R9T1V3X5Z7B9D1FG");
console.log(result.deleted, result.id);
Delete a stream: fields, response and errors
POST/v1/audit/orgs/{id}/streams/{stream_id}/testSend a test delivery
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const result = await client.audit.streams.test("org_8472", "astr_01J0Y3N5P7R9T1V3X5Z7B9D1FG");
console.log(result.delivered, result.http_status, result.error);
Send a test delivery: fields, response and errors
POST/v1/audit/portal_sessionsCreate a portal session
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const session = await client.audit.portalSessions.create({
  organizationId: "org_8472",
  intent: "audit_logs",
  sessionDurationSeconds: 3600,
});
console.log(session.url, session.link_expires_in, session.session_expires_in);
Create a portal session: fields, response and errors
POST/v1/audit/exportsCreate an export
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const job = await client.audit.exports.create({
  organizationId: "org_8472",
  format: "ndjson",
  filters: {
    actions: "user.signed_in,user.signed_out",
    occurred_after: "2026-09-01T00:00:00Z",
  },
});
console.log(job.id, job.status);
Create an export: fields, response and errors
GET/v1/audit/exports/{id}Get an export
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

let job = await client.audit.exports.get("aexp_01J0Y4Q6S8V0X2Z4B6D8F0H2JK");
while (job.status === "pending" || job.status === "running") {
  await new Promise((r) => setTimeout(r, 5000));
  job = await client.audit.exports.get("aexp_01J0Y4Q6S8V0X2Z4B6D8F0H2JK");
}
console.log(job.status, job.row_count, job.download_url ?? job.error);
Get an export: fields, response and errors
POST/v1/audit/portal/exchangeExchange a portal link token
Node.js
// No API key: the exchange is public and the link token is the credential.
const linkToken = process.env.PORTAL_LINK_TOKEN;

const res = await fetch("https://api.invoance.com/v1/audit/portal/exchange", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ token: linkToken }),
});
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const session = await res.json();
console.log(session.intent, session.expires_in);
// session.token is the Bearer token for the /v1/audit/portal/* routes.
Exchange a portal link token: fields, response and errors
GET/v1/audit/portal/eventsList events through the portal
Node.js
// Portal reads use the short-lived JWT from POST /v1/audit/portal/exchange,
// not an API key. PORTAL_TOKEN holds that JWT.
const portalToken = process.env.PORTAL_TOKEN;

const url = new URL("https://api.invoance.com/v1/audit/portal/events");
url.searchParams.set("actions", "user.signed_in");
url.searchParams.set("limit", "50");

const res = await fetch(url, { headers: { Authorization: "Bearer " + portalToken } });
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const page = await res.json();
for (const event of page.events) {
  console.log(event.seq, event.action, event.actor.id);
}
console.log(page.next_cursor);
List events through the portal: fields, response and errors
GET/v1/audit/portal/events/{id}Get an event through the portal
Node.js
// Portal reads use the short-lived JWT from POST /v1/audit/portal/exchange,
// not an API key. PORTAL_TOKEN holds that JWT.
const portalToken = process.env.PORTAL_TOKEN;

const res = await fetch("https://api.invoance.com/v1/audit/portal/events/aevt_01J0Y1Z2A3B4C5D6E7F8G9H0JK", {
  headers: { Authorization: "Bearer " + portalToken },
});
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const event = await res.json();
console.log(event.seq, event.action, event.payload_hash);
Get an event through the portal: fields, response and errors
GET/v1/audit/portal/events/{id}/verifyVerify an event through the portal
Node.js
// Portal reads use the short-lived JWT from POST /v1/audit/portal/exchange,
// not an API key. PORTAL_TOKEN holds that JWT.
const portalToken = process.env.PORTAL_TOKEN;

const res = await fetch("https://api.invoance.com/v1/audit/portal/events/aevt_01J0Y1Z2A3B4C5D6E7F8G9H0JK/verify", {
  headers: { Authorization: "Bearer " + portalToken },
});
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const result = await res.json();
console.log(result.valid, result.reason, result.key_source);
Verify an event through the portal: fields, response and errors
GET/v1/audit/portal/orgGet the portal's org and issuer
Node.js
// Portal reads use the short-lived JWT from POST /v1/audit/portal/exchange,
// not an API key. PORTAL_TOKEN holds that JWT.
const portalToken = process.env.PORTAL_TOKEN;

const res = await fetch("https://api.invoance.com/v1/audit/portal/org", {
  headers: { Authorization: "Bearer " + portalToken },
});
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const info = await res.json();
console.log(info.issuer.name, info.org.name, info.intent);
Get the portal's org and issuer: fields, response and errors
GET/v1/audit/portal/streamsList streams through the portal
Node.js
// Portal reads use the short-lived JWT from POST /v1/audit/portal/exchange,
// not an API key. PORTAL_TOKEN holds that JWT.
const portalToken = process.env.PORTAL_TOKEN;

const res = await fetch("https://api.invoance.com/v1/audit/portal/streams", {
  headers: { Authorization: "Bearer " + portalToken },
});
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const { streams } = await res.json();
for (const stream of streams) {
  console.log(stream.id, stream.state, stream.endpoint);
}
List streams through the portal: fields, response and errors
POST/v1/audit/portal/streamsCreate a stream through the portal
Node.js
// Portal reads use the short-lived JWT from POST /v1/audit/portal/exchange,
// not an API key. PORTAL_TOKEN holds that JWT.
const portalToken = process.env.PORTAL_TOKEN;

const res = await fetch("https://api.invoance.com/v1/audit/portal/streams", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + portalToken,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ type: "webhook", url: "https://siem.example.com/hooks/invoance" }),
});
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const stream = await res.json();
// Store signing_secret now; it is not returned again.
console.log(stream.id, stream.signing_secret);
Create a stream through the portal: fields, response and errors
DELETE/v1/audit/portal/streams/{id}Delete a stream through the portal
Node.js
// Portal reads use the short-lived JWT from POST /v1/audit/portal/exchange,
// not an API key. PORTAL_TOKEN holds that JWT.
const portalToken = process.env.PORTAL_TOKEN;

const res = await fetch("https://api.invoance.com/v1/audit/portal/streams/astr_01J0Y3N5P7R9T1V3X5Z7B9D1FG", {
  method: "DELETE",
  headers: { Authorization: "Bearer " + portalToken },
});
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const result = await res.json();
console.log(result.deleted, result.id);
Delete a stream through the portal: fields, response and errors
POST/v1/audit/portal/streams/{id}/testTest a stream through the portal
Node.js
// Portal reads use the short-lived JWT from POST /v1/audit/portal/exchange,
// not an API key. PORTAL_TOKEN holds that JWT.
const portalToken = process.env.PORTAL_TOKEN;

const res = await fetch("https://api.invoance.com/v1/audit/portal/streams/astr_01J0Y3N5P7R9T1V3X5Z7B9D1FG/test", {
  method: "POST",
  headers: { Authorization: "Bearer " + portalToken },
});
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const result = await res.json();
console.log(result.delivered, result.http_status, result.error);
Test a stream through the portal: fields, response and errors
GET/v1/proof/audit/{event_id}Get the public proof of an audit event
Node.js
// No API key: the public proof endpoint is unauthenticated.
const eventId = "aevt_01J0Y1Z2A3B4C5D6E7F8G9H0JK";

const res = await fetch("https://api.invoance.com/v1/proof/audit/" + eventId);
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const proof = await res.json();
console.log(proof.organization.issuer_name, proof.event.action, proof.event.seq);
console.log(proof.verification.valid, proof.verification.reason);
Get the public proof of an audit event: fields, response and errors
POST/v1/proof/audit/{event_id}/verifyVerify a copy of an audit event
Node.js
import { readFile } from "node:fs/promises";

// No API key: the public verify endpoint is unauthenticated.
// event.json holds the event exactly as get, an export or a stream delivered it.
const event = JSON.parse(await readFile("event.json", "utf8"));

const res = await fetch("https://api.invoance.com/v1/proof/audit/" + event.id + "/verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ event }),
});
if (!res.ok) {
  throw new Error(res.status + " " + (await res.text()));
}
const result = await res.json();
console.log(result.match_result, result.signature_valid, result.reason);
Verify a copy of an audit event: fields, response and errors
PlatformReference
GET/v1/meIntrospect the API key
Node.js
import { InvoanceClient } from "invoance";

// Reads INVOANCE_API_KEY from the environment.
const client = new InvoanceClient();

const me = await client.me();
console.log(me.organization.primary_domain, me.organization.plan_tier);
console.log(me.api_key.scopes, me.limits.rate_limit_per_sec);
Introspect the API key: fields, response and errors
GET/keys/{domain}Fetch an organization's public key
Node.js
import { createPublicKey, verify } from "node:crypto";

const domain = "acme.com";
const eventId = "7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4";

// 1. The key for the issuer's verified domain (no API key needed).
const keyRes = await fetch("https://api.invoance.com/keys/" + domain);
if (!keyRes.ok) throw new Error("key lookup failed: " + keyRes.status);
const key = await keyRes.json();

// 2. The signed record, from the public event proof endpoint.
const proofRes = await fetch("https://api.invoance.com/v1/proof/event/" + eventId);
if (!proofRes.ok) throw new Error("proof lookup failed: " + proofRes.status);
const { event } = await proofRes.json();

// 3. Raw 32-byte Ed25519 key to SPKI DER, which node:crypto can load.
const raw = Buffer.from(key.public_key, "base64url");
const spki = Buffer.concat([Buffer.from("302a300506032b6570032100", "hex"), raw]);
const pinned = createPublicKey({ key: spki, format: "der", type: "spki" });

// 4. The record must name the same key, and the signature must verify with it.
const sameKey = Buffer.from(event.public_key, "hex").equals(raw);
const signatureValid = verify(
  null,
  Buffer.from(event.signed_payload, "hex"),
  pinned,
  Buffer.from(event.signature, "hex"),
);
console.log(key.key_id, sameKey, signatureValid);
Fetch an organization's public key: fields, response and errors
GET/v1/proof/event/{event_id}Read an event's public proof
Node.js
const eventId = "7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4";

const res = await fetch("https://api.invoance.com/v1/proof/event/" + eventId);
if (!res.ok) throw new Error("proof lookup failed: " + res.status);
const { organization, event } = await res.json();

console.log(organization.primary_domain, organization.domain_verified);
console.log(event.event_type, event.payload_hash, event.signature_alg);
Read an event's public proof: fields, response and errors
POST/v1/proof/event/{event_id}/verifyVerify an event hash publicly
Node.js
const eventId = "7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4";

const res = await fetch("https://api.invoance.com/v1/proof/event/" + eventId + "/verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    payload: {
      policy_id: "pol_8472",
      approved_by: "risk_committee",
      decision: "approved",
    },
  }),
});
if (!res.ok) throw new Error("verify failed: " + res.status);
const result = await res.json();

console.log(result.match_result, result.signature_valid, result.method);
Verify an event hash publicly: fields, response and errors
GET/v1/proof/{event_id}/organizationRead a document anchor's public proof
Node.js
const eventId = "3f9d2a71-5c6e-4b8a-9d1f-8e2c47b0a5d3";

const res = await fetch("https://api.invoance.com/v1/proof/" + eventId + "/organization");
if (!res.ok) throw new Error("proof lookup failed: " + res.status);
const { organization, event } = await res.json();

console.log(organization.issuer_name, organization.domain_verified);
console.log(event.event_id, event.created_at);
Read a document anchor's public proof: fields, response and errors
POST/v1/proof/{event_id}/verifyVerify a document hash publicly
Node.js
import { createHash } from "node:crypto";
import { readFile } from "node:fs/promises";

const eventId = "3f9d2a71-5c6e-4b8a-9d1f-8e2c47b0a5d3";
const documentHash = createHash("sha256").update(await readFile("./contract.pdf")).digest("hex");

const res = await fetch("https://api.invoance.com/v1/proof/" + eventId + "/verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ document_hash: documentHash }),
});
if (!res.ok) throw new Error("verify failed: " + res.status);
const result = await res.json();

console.log(result.match_result, result.signature_valid, result.anchored_at);
Verify a document hash publicly: fields, response and errors
GET/v1/proof/ai/{attestation_id}Read an AI attestation's public proof
Node.js
const attestationId = "a1d4f8c2-7b3e-4e9a-b5c6-0d2e8f4a7c19";

const res = await fetch("https://api.invoance.com/v1/proof/ai/" + attestationId);
if (!res.ok) throw new Error("proof lookup failed: " + res.status);
const { organization, attestation } = await res.json();

console.log(organization.primary_domain, organization.domain_verified);
console.log(attestation.attestation_type, attestation.model_name, attestation.output_hash);
Read an AI attestation's public proof: fields, response and errors
POST/v1/proof/ai/{attestation_id}/verifyVerify an AI content hash publicly
Node.js
import { createHash } from "node:crypto";

const attestationId = "a1d4f8c2-7b3e-4e9a-b5c6-0d2e8f4a7c19";
const output = "Either party may terminate with 30 days written notice. Early termination fees do not apply after month 12.";
const contentHash = createHash("sha256").update(output).digest("hex");

const res = await fetch("https://api.invoance.com/v1/proof/ai/" + attestationId + "/verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ content_hash: contentHash }),
});
if (!res.ok) throw new Error("verify failed: " + res.status);
const result = await res.json();

console.log(result.match_result, result.matched_field, result.signature_valid);
Verify an AI content hash publicly: fields, response and errors
Verify offlineHow verification works

Two checks run without trusting the server: attestations.verifySignature fetches the record and checks its Ed25519 signature over signed_payload; verifyAuditEvent rebuilds the invoance.audit/1 bytes of an audit event and checks its signature. Pass publicKey to pin the key from GET /keys/{domain} instead of the key on the row.

Node.js
import { InvoanceClient, verifyAuditEvent } from "invoance";

const client = new InvoanceClient();

// AI attestation: Ed25519 over signed_payload, checked locally.
const sig = await client.attestations.verifySignature("a1d4f8c2-7b3e-4e9a-b5c6-0d2e8f4a7c19");
console.log(sig.valid, sig.reason);

// Audit event: canonical bytes rebuilt locally, signature checked
// against a pinned key (the public_key from GET /keys/{domain}, base64url decoded to hex).
const pinnedHexKey = "d4443bd9d30ef4c2e0e5db03467e3c5c740358482c1a1e30cdb27a2e02a38176";
const event = await client.audit.events.get("aevt_01J8F3KQ2R7VWX9YB4ND6MCZAH");
const result = verifyAuditEvent(event, { publicKey: pinnedHexKey });
console.log(result.valid, result.reason, result.keySource); // keySource: "pinned"

Proof infrastructure. Records are hashed, signed with your organization's Ed25519 key, and stored append-only, so anyone can check them later.

Products

  • Audit Logs
  • Event Ledger
  • AI Attestation
  • Document Anchoring
  • Traces

Developers

  • Documentation
  • API reference
  • SDKs
  • How it works
  • How traces seal
  • System status

Verify

  • Audit Log
  • Event
  • AI Attestation
  • Document
  • Trace

Company

  • Why Invoance
  • Pricing
  • Security
  • Compliance teams
  • Finance teams
  • Partners
  • Resources
  • Help center
  • Contact
© 2026 Invoance
PrivacyLegal noticeLegal FAQGitHubLinkedInX