Skip to main content
Every record envelope — action, retrieval, and human-adjudication decisions alike — is attested by a decision receipt: an Ed25519 signature over the decision’s canonical payload, stored separately from the envelope it proves. Receipts are then Merkle-batched under an HSM-signed root, timestamped by an independent authority, and chained into an append-only transparency log. This page specifies the exact cryptography so you — or your auditor — can verify it independently.
Receipt issuance is plan-dependent. Decisions on every plan are still recorded in the queryable audit logs.

What a receipt contains

Once the receipt is committed to a batch it also carries its Merkle coordinates: the batch it belongs to, its leaf index, and its leaf hash. The dashboard’s record verification page surfaces all of these fields for any record.

When receipts are issued

Signing is asynchronous — scheduled immediately after the envelope persists, entirely off the decision hot path. Your agents never wait on cryptography; a decision’s latency is identical with receipts on or off. Asynchronous does not mean best-effort. Unbatched receipts are the durable batching queue: if a batching sweep fails, the next sweep picks up the same receipts. A record’s verification result reports attestationStatus: "timestamp_pending" between signing and batch commitment — typically a minute or two — and "signed" once the full chain verifies.

The exact cryptography

Canonicalization

The signed payload is the envelope’s event object, serialized deterministically:
  1. Object keys are sorted alphabetically, recursively (arrays keep their order; primitives pass through unchanged).
  2. The sorted structure is serialized with compact JSON.stringify — no whitespace.
  3. The signature and hash operate on the UTF-8 bytes of that string.

Hash and signature

  • payload_hash = SHA-256 over the canonical bytes, hex-encoded.
  • signature = Ed25519 over the canonical payload bytes themselves — not over the hash.
The most common verification mistake is signing-recipe drift: verifying the Ed25519 signature against the SHA-256 hash, decoding fields as standard base64 instead of base64url, or parsing public_key as a raw 32-byte key instead of SPKI DER. Any one of these makes every genuine receipt appear forged. The sample below matches the real recipe.

Key management

In production the signing key is mandatory — the signer refuses to fall back to an ephemeral key, so a receipt that exists is always verifiable against the published key. Receipts produced by the hardened strategies record which one signed them (a receipt with no recorded strategy was signed by the default strategy), and an optional hardened mode signs every receipt inside the HSM itself so the private key never enters an application process (for those receipts, the signed message is the 32-byte payload_hash digest rather than the canonical bytes — batch roots are signed the same way). The receipt’s stored public_key is authoritative for verification, so key rotation never invalidates history.
Ask the platform to re-derive and re-check the entire attestation chain for a record:
Checks fail closed: a check that cannot be completed reports pass: false with a reason — never a silent pass — with one deliberate exception: the ingest anchor on legacy records that predate anchor recording. verified is true only when all applicable checks pass. The Merkle inclusion proof is recomputed on demand from the batch’s retained leaf set — it must reproduce the signed root exactly — and the root check performs a live AWS KMS Verify round-trip, confirming the HSM key itself vouches for the signature. These endpoints sit on the management surface: harness keys used by your agents are deliberately confined to the operational SDK routes and receive 403 here. The dashboard’s record verification page runs the identical checks — click any record pill under Harness → Runtime Enforcement. For scripted access, see Platform Automation.

Verify offline (TypeScript)

Receipts also verify with no VisIQ dependency at all — Node’s built-in crypto is enough. Copy the event and receipt fields from the record’s verification page in the dashboard:
This verifies the default signing strategy. A receipt whose recorded signing strategy is the HSM-per-receipt mode signs the 32-byte payload_hash digest instead — substitute Buffer.from(receipt.payload_hash, "hex") as the message in step 3. The one-call endpoint above handles both automatically.

Merkle inclusion and the checkpoint chain

Receipts are batched into an RFC 6962-style Merkle tree with domain-separated hashing:
  • Leaf hash = SHA-256( 0x00 ‖ payload_hash_bytes )
  • Node hash = SHA-256( 0x01 ‖ left ‖ right )
  • An unpaired trailing node is promoted unchanged to the next level — never hashed with a copy of itself.
The batch root is signed once with the HSM-backed key, and one RFC 3161 timestamp covers the root — so a single signature and a single timestamp attest every receipt in the batch via its inclusion proof. That is what makes 100% signing-and-timestamping coverage hold at any decision volume. Batches then form an append-only hash chain: each batch carries a monotonic sequence number, a commitment to the previous batch’s root, and a running accumulator
with the batch signature covering chain_hash — so one trusted tip signature vouches for the entire history. Deleting a batch leaves a gap, reordering breaks the accumulator, and editing any root breaks the recomputation. Two management-API endpoints expose this to any authenticated caller (the feed itself is tenant-neutral — it contains only roots, signatures, and counts):
  • GET /record/checkpoints — the transparency-log checkpoint feed: signed roots, signatures, leaf counts, and timestamp times, newest first. Also browsable in the dashboard under Settings → Checkpoint feed (organization scope).
  • GET /record/chain/consistency — walks a chain segment and proves, purely by recomputation, that no batch was deleted, reordered, or tampered with.
Checkpoints are additionally published to write-once (WORM) object storage under compliance-mode object locking — an externally held copy that neither VisIQ nor its cloud provider can alter or delete before retention expires. A silent rewrite of history is therefore detectable even by us: the audit trail does not ask you to trust the party that operates it.

RFC 3161 trusted timestamps

Each batch root is countersigned by DigiCert’s timestamp authority. The DER-encoded timestamp token binds the root hash to a time asserted by DigiCert — an independent third party — and verification checks the token against DigiCert’s certificate chain. Combined with the chain above, this proves a decision existed no later than the attested time, on evidence that does not depend on VisIQ’s clocks or word. For long-horizon audits, batches can also carry frozen revocation evidence for the timestamp certificate chain, so tokens remain independently verifiable years later, after certificates expire or responders disappear.

Next steps

Audit Trail

What gets recorded, the envelope schema, and how to consume the trail.

Platform Automation

Authenticate scripts and CI against the management API.