Proof
Show what followed, line by line.
For governed interactions a compliance receipt is visible in the product. It records what the system received, what it decided and what it released — as hashes, chained to the receipt before it and gathered into a Merkle root. Three of those elements can be recomputed today by anyone holding the receipt: no key, no account, no access to our database.
Compliance receipt
Worked example- Input hash
0x92f2242f4701ee89…83b61ceaNo key needed- Output hash
0x8a09586162b314e2…d79c6b92No key needed- Evidence hash
0xa8154f5f53e495a5…af2231baNo key needed- Signature
0xed8c2d6ef474c9e5…1433dd3cAudact's key needed
Worked example. Acme GmbH and Nova Industries are fictional; no customer data appears here. These are values from the sample receipt at /sample-receipt.json. /receipt-explorer recomputes the three key-free values in your own browser: input hash, output hash and evidence hash. The authentication code is computed under a symmetric key held by Audact and cannot be verified without it.
Current evidence state
- Receipt in the productVisible
- Production export (measured on browser calls rather than over a telephone line)Working today · retested on 26 August 2026 after the deploy
- Three hash checksPublic
- External root publicationWorking today
- Public issuer verificationNot available
Five states, not one. Each is set out below, with what it rests on.
Field by field
What a receipt holds
A receipt is one object per governed interaction. Most of it is a record: you can read it, and reading it tells you what the system believed at the time. Three fields can be recomputed by anyone holding nothing but the receipt: no key, no account, no access to our systems. The authentication code is computed under a symmetric key held by Audact: it authenticates the receipt but cannot be verified without the key.
- Field
- receipt_format_version
- What it records
- The receipt schema version. '1.0.0' in this sample.
- Check
- Read
- Field
- call_id
- What it records
- The unique identifier of the interaction.
- Check
- Read
- Field
- timestamp
- What it records
- When the receipt was written, by the platform's clock.
- Check
- Read
- Field
- input_hash
- What it records
- SHA-256 of the input text, as the system received it.
- Check
- Recompute
- Field
- output_hash
- What it records
- SHA-256 of the output text, as the system released it. MODIFY verdict: differs from input_hash.
- Check
- Recompute
- Field
- verdict
- What it records
- The gate decision: ALLOW, BLOCK or MODIFY.
- Check
- Read
- Field
- config_version
- What it records
- The configuration version active at the time of the interaction.
- Check
- Read
- Field
- config_seal_hash
- What it records
- SHA-256 of the configuration at that version.
- Check
- Read
- Field
- policy_version
- What it records
- The policy version applied to this interaction.
- Check
- Read
- Field
- evidence_hash
- What it records
- SHA-256 of the preceding evidence event in the call's evidence chain.
- Check
- Recompute
- Field
- auth_mechanism
- What it records
- The authentication algorithm: 'hmac-sha256'.
- Check
- Read
- Field
- signature
- What it records
- HMAC-SHA256 over the signing payload under a symmetric key held by Audact.
- Check
- Key needed
Every name in this column is a field of the sample receipt at /sample-receipt.json, spelled the way the file spells it: open the file and each one is there.
The chain
Each receipt names the one before it.
A receipt does not stand on its own. Before it is written, the hash of the preceding receipt is folded into it, so the receipts of one tenant form a single ordered chain.
That is what makes an edit show. Change a value in one receipt and its hash changes; the receipt after it still carries the old hash, and the two stop matching. Nothing here prevents a change; it makes a change visible to anyone who walks the chain.
Receipt RCP-899
- Carries the hash of
0xc15f…df07- Its own hash
0xe48f…5a07
Receipt RCP-900
- Carries the hash of
0xe48f…5a07- Its own hash
0x627d…9389
Receipt RCP-901
- Carries the hash of
0x627d…9389- Its own hash
0xfb45…4fd2
If one changes
Every receipt after it stops matching, and the first mismatch names the position where the chain broke. Append-only is how we write. Detectable is what you can check.
Audit log
Append-only event chain. Any later edit or reordering is detectable by recomputing the chain against the commitment we kept.
Inclusion
Recompute the root yourself.
Receipts are aggregated into Merkle roots per tenant; the roots are published at api.audact.ai/v1/metachain. The four steps below show the path recomputation on the older illustrative sample, which carries the path fields.
- Path from this receipt
- Sibling hashes it uses
- Other receipts in the batch
Four steps
- 1
Hash the five core fields
Take receipt_id, issued_at, input_hash, output_hash and previous_receipt_hash, write them in one fixed form (keys in alphabetical order, no whitespace) and take the SHA-256. That value is the leaf, and the receipt carries it as receipt_hash. It is not a hash over the whole receipt.
- 2
Fold in the first sibling
Decode the leaf and the first hash in merkle.path back to bytes, put the sibling on the side its side field names, join the two and take the SHA-256 of the pair.
- 3
Walk up
Repeat for each remaining entry in merkle.path, one level at a time, until a single value is left.
- 4
Compare
Set that value against merkle.root. Equal means this receipt matches the root the file itself carries. To confirm inclusion, that root is checked against the published root at api.audact.ai/v1/metachain with the inclusion proof in the call's Article 50 report.
None of those four steps uses a key: the receipt and its path are enough. What they establish is that the receipt fits the root it carries. The inclusion in the published root is checked with the inclusion proof in the call's Article 50 report; the roots are at api.audact.ai/v1/metachain.
From the older illustrative sample
- Field
- receipt_hash
- As published
- 0xfb45e410edb4a3aa…ecb14fd2
- Field
- merkle.leaf_index
- As published
- 2
- Field
- merkle.path
- As published
- right · left · right
- Field
- merkle.root
- As published
- 0x8a11d892e1e07458…e1141396
Check by check
Seven checks, and they are not equally available.
Recomputing the Merkle path up to the root a receipt carries is not the same check as setting that root against the published root at api.audact.ai/v1/metachain with the inclusion proof from the call's Article 50 report. The first you can do today, in the worked example. The second uses the inclusion proof from the call's Article 50 report. Each row below says what the check rests on and where it stands.
- Check
- Recompute the input hash
- What it rests on
- SHA-256 over the input block of the receipt in your hand. Nothing else is needed.
- State
- Available
- Check
- Recompute the output hash
- What it rests on
- SHA-256 over the output block of the same file.
- State
- Available
- Check
- Recompute the hash of the preceding evidence event
- What it rests on
- SHA-256 of the preceding evidence event in the call's evidence chain. The event's fields are pipe-delimited in a fixed order and the receipt carries the hash as evidence_hash.
- State
- Available
- Check
- Recompute the Merkle path to the root the receipt carries
- What it rests on
- Fold the leaf up through merkle.path and set it against merkle.root — the root printed in the same file. Receipts are aggregated into Merkle roots per tenant; the roots are published at api.audact.ai/v1/metachain, and inclusion is checked with the inclusion proof from the call's Article 50 report. The steps run on /sample-receipt.json; production export worked when it was retested on 26 August 2026 after the deploy, measured on browser calls rather than over a telephone line.
- State
- Available in the worked example
- Check
- Set that root against a commitment published outside our systems
- What it rests on
- A fourth, inclusion in the Merkle root, is checked with the inclusion proof in the call's Article 50 report: the customer exports the report and can hand it to a reviewer, who sets the proof against the published root.
- State
- Working today
- Check
- Establish who issued the receipt using public cryptography alone
- What it rests on
- The receipt carries HMAC-SHA256 under a symmetric key held by Audact. There is no freely available key to check it with, so there is nothing for a third party to check against.
- State
- Not available
- Check
- Hold the issuer to it if they deny writing it
- What it rests on
- A message authentication code under a shared key provides no non-repudiation: whoever can check it can also produce it, and we hold the same key. It is not a signature.
- State
- Not provided by the current HMAC design
/receipt-explorer performs the first three of these on the worked example, in your browser. No public service checks a receipt on behalf of a third party today.
Check it yourself
Three values, recomputable by anyone.
Start on the left: three values anyone holding a receipt can recompute today, without a key and without us. A fourth, inclusion in the Merkle root, is checked against the published root with the inclusion proof from the call's Article 50 report. Beside it stands what the key is for and what a receipt is a record of. So the first column can be taken literally instead of on trust.
Three values, recomputable by anyone
The input hash, the output hash, the link to the receipt before it. Inclusion in the Merkle root is the fourth check; it is checked against the published root with the inclusion proof from the call's Article 50 report.
No key, no account and no access to our database: the arithmetic runs on the receipt in your hand.
What the key is for
The code is HMAC-SHA256 over the canonical receipt, under a symmetric key held by Audact. It is a message authentication code and not a public-key scheme; there is no freely available key to check it with.
Whoever can check the code can also produce it, and we hold the same key. It evidences that the record is intact, not who wrote it.
What a receipt is about, and what it is not
A receipt is a faithful record of what the system received, decided and released. That is what it establishes, not whether the world matched it.
If a caller gave a wrong name, the receipt records the wrong name faithfully. Proof of process is not proof of fact, and no cryptography closes that gap.
Do it yourself
Take a receipt apart.
The explorer walks the worked example field by field, with the sample files next to it. None of it needs an account.
- Receipt explorer
Walk the worked example field by field.
- Sample receipt (JSON)
Fictional parties, real arithmetic: three values recompute from the file alone, and the fourth folds up to the Merkle root printed in the same file.
- Sample receipt (PDF)
The same record in a form a data protection officer can read.
- Evidence Vault API
How receipts are written and fetched.
- How to recompute it — the exact form
The canonical form, which block feeds which value, and four test vectors to tune against. No code of ours.
Evidence chain
Three of those elements can be recomputed today by anyone holding the receipt: no key, no account, no access to our database.
Checking the authentication code uses the symmetric key we issue to your tenant.
Control what AI can cause. Prove what follows.
Where a receipt comes from
A receipt is what a governed call leaves behind.
Voice is the application it comes out of: telephony, the Article 50 disclosure and country policy in one place, with a receipt visible in the product for governed interactions.
