Skip to main content
Audact
See the offer

Receipt explorer

Recompute a receipt in your own browser.

An example receipt is loaded below and already checked — nothing to press. Three of its values recompute without a key, here, in your own browser: the input hash, the output hash, and the evidence hash of the preceding chain event. Paste your own receipt over the example, or change one digit and watch. Nothing is sent to us.

What has been checked
Recomputing…
Input hash
—Recomputing…
Output hash
—Recomputing…
Evidence hash
—Recomputing…

Edit any value and the three checks follow along as you type.

Example receipt in the production format: synthetic values, no real interaction.

The three checks

  • Input hashRecomputing…

    SHA-256 over the raw UTF-8 text of sample_texts.input.

    Recomputed here
    —
    In the receipt
    —
  • Output hashRecomputing…

    SHA-256 over the raw UTF-8 text of sample_texts.output. Verdict rule (F21): ALLOW: output equals input; MODIFY or BLOCK: output differs.

    Recomputed here
    —
    In the receipt
    —
  • Evidence hashRecomputing…

    SHA-256 over the pipe-delimited pre-image of preceding_event: event_id, call_id, sequence, event_type, timestamp, canonicalJSON(data), previous_hash.

    Recomputed here
    —
    In the receipt
    —

Authentication and Merkle

What cannot be checked on this page.

A receipt carries an HMAC-SHA256 authentication code, computed over the signing payload under a key held by Audact. Recomputing it requires that key. The signing payload — the version prefix and the receipt without the signature field, canonicalised as RFC 8785 JCS — is shown below so the structure is visible.

Merkle inclusion is not checked here: the explorer holds no inclusion proof. The proof is in the call's Article 50 report and is checked against the root published at api.audact.ai/v1/metachain.

Authentication code in this receipt—

Change one digit in the receipt and watch the row that depends on it stop matching.

Without this page

The same three checks in a terminal.

The same three checks in a terminal. It prints ok three times against this file.

The canonical form is the part people miss: two JSON texts that mean the same thing can be different bytes, and then the hashes differ while nothing has changed. Keys sorted, no whitespace — that is the RFC 8785 ordering for this file's value types (strings and integers). It is written out at /sample-receipt-readme.txt together with the three recomputations and what cannot be checked.

import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
const r = JSON.parse(readFileSync("sample-receipt.json", "utf8"));
const sha = (s) => createHash("sha256").update(s).digest("hex");
// Canonical form: RFC 8785 (JCS), prefixed `audact-receipt-version:<receipt_format_version>\n` for the authentication code.
const canon = (v) => {
  if (v === null || typeof v !== "object") return JSON.stringify(v) ?? "null";
  if (Array.isArray(v)) return "[" + v.map(canon).join(",") + "]";
  const keys = Object.keys(v).sort();
  return "{" + keys.map((k) => JSON.stringify(k) + ":" + canon(v[k])).join(",") + "}";
};
const e = r.preceding_event;
const evidenceHash = sha(
  [e.event_id, e.call_id, e.sequence, e.event_type, e.timestamp, canon(e.data), e.previous_hash].join("|")
);
const results = [
  ["input_hash",    sha(r.sample_texts.input),  r.receipt.input_hash],
  ["output_hash",   sha(r.sample_texts.output), r.receipt.output_hash],
  ["evidence_hash", evidenceHash,               r.receipt.evidence_hash],
].map(([name, got, want]) => { console.log(`${got === want ? "ok  " : "FAIL"} ${name}`); return [name, got === want]; });
process.exitCode = results.every(([, ok]) => ok) ? 0 : 1;

Where this fits

A receipt is what a call leaves behind.

Every governed interaction produces one: what went in, what was decided, the policy version, and the link to the interaction before it. The chain is append-only; a later edit or reordering shows up when the chain is recomputed against the stored commitment.

Article 50 of the EU AI Act has applied since 2 August 2026. It is a transparency duty: people are told they are dealing with an AI system. A receipt is how you show, afterwards, the approved disclosure text and when its audio finished being sent, the policy version in force, and the decision — with the input and the output stored as hashes rather than words.

Next

Put your own calls behind this.

A receipt like the one you just checked comes out of every governed interaction. Agencies run it for their clients; enterprises run it for their own regulated work.