@datahubz/attest
v1.2.0
Published
Attest Integrations client: record events, daily zero-knowledge state proofs, Proof Cards and certificates for the organizations your platform serves, each from its own wallet on Horizen, verified on zkVerify.
Maintainers
Readme
@datahubz/attest
The client for Attest Integrations: record what happens at the organizations your platform serves, prove each one's state every day, and issue Proof Cards and certificates, with evidence anyone can check.
- Every organization gets its own wallet on Horizen, and every record is its own transaction from it. Nothing is batched.
- Each day's state is committed, chained to the day before, and proven in zero knowledge (Groth16), with the proof verified on zkVerify. Metric values stay private.
- Every record has a public verification page that anyone can use to check it.
One file, no dependencies. Node 18+, Deno, Bun, and edge runtimes.
npm install @datahubz/attestQuickstart
import { Attest } from "@datahubz/attest";
const attest = new Attest({ apiKey: process.env.ATTEST_API_KEY! }); // ik_live_..., server-side only
// 1. Register an organization you serve (idempotent on externalRef). Its wallet is created on the spot.
await attest.organizations.upsert({ externalRef: "hotel-42", name: "Pousada Aysú" });
// 2. Record an event: anchored on Horizen in its own transaction, usually within seconds.
await attest.events.record({
organization: "hotel-42",
type: "statement.closed",
subject: statement.id,
data: statement, // fingerprinted, never kept; or pass `digest` to keep the data on your side
idempotencyKey: `statement-${statement.id}-closed`,
});
// 3. Record the day's state: committed, proven in zero knowledge, verified on zkVerify, anchored on Horizen.
const day = await attest.snapshots.record({
organization: "hotel-42",
stream: "hotel.daily",
state: dailyState,
metrics: [
{ name: "bookings", value: 14 },
{ name: "unreconciled_payouts", value: 0, check: { op: "eq", value: 0 } },
{ name: "revenue_cents", value: 1845000 },
],
});
// Store day.opening.salt: with the metric values, it opens the commitment to an auditor.Proof Cards
Your organizations can issue W3C Verifiable Credentials to the people they work with. Each card is signed with the organization's own key and anchored from its wallet; the recipient gets an email to accept it.
const card = await attest.credentials.issue({
organization: "hotel-42",
template: "membership", // training | supplier | membership | employment | custom
title: "Owner portal access",
recipient: { email: "[email protected]", name: "Mary Ruiz" },
fields: { memberSince: "2026-09-29" },
idempotencyKey: `access-${membership.id}`,
});
await attest.credentials.setStatus(card.id, "revoke", { reason: "Access removed" }); // or "suspend" | "reinstate"Certificates
Certificates about your organizations are issued by the organization DataHubz assigns to your platform, signed by the people you name with their passkeys, and published on Attest. Link to url; the certificate lives on Attest only.
const cert = await attest.certificates.create({
organization: "hotel-42",
title: "Annual operations review",
subjectName: "Pousada Aysú",
statement: "Every statement for the year was closed, sent and paid.",
asOf: new Date(),
sections: [{ heading: "Scope", items: [{ label: "Owner statements", result: "Complete" }] }],
signers: [{ email: "[email protected]", name: "Mary Ruiz", role: "Controller" }],
idempotencyKey: `review-2026-${hotel.id}`,
});
// cert.signUrl: where the signers sign. cert.url: the public certificate once issued.Certificates stay out of search results unless the organization wants them found: pass searchable: true, or later await attest.certificates.setSearchable(cert.id, true). A listed certificate leaves search results on its own once it is revoked, replaced or expired.
Keeping data on your side
import { digest, digestBytes } from "@datahubz/attest";
await attest.events.record({ organization: "hotel-42", type: "document.signed", digest: await digestBytes(pdfBytes) });
await attest.snapshots.record({ organization: "hotel-42", stream: "hotel.daily", digest: await digest(state), metrics });digest(json) gives exactly the fingerprint Attest computes for data; digestBytes(bytes) fingerprints a file.
Webhooks
const event = await Attest.verifyWebhook(rawBody, request.headers.get("attest-signature"), process.env.ATTEST_WEBHOOK_SECRET!);
// event.type: event.anchored | event.failed | snapshot.anchored | snapshot.verified | snapshot.failed | pingReliability
Network errors, 429 and 5xx are retried with backoff. Every write is idempotent: events, Proof Cards and certificates carry an idempotency key (one is generated if you don't pass yours), and a daily state is unique per organization, stream and day. Errors are AttestError with status and code; organization_excluded means the organization was excluded and can be skipped.
Documentation
Guide and API reference: https://attest.datahubz.com/docs/integrations
License
MIT
