Receipts and Verification¶
Every settled marketplace job leaves a supplier-signed receipt whose hash is committed on-chain by the supplier's own key before settlement can move, with acceptance and settlement recorded as transactions at a public script address - independently verifiable by anyone holding the receipt.
This page defines the artifact precisely and gives the verification recipe.
What a receipt is¶
Three linked artifacts - only one lives on-chain:
| Artifact | Where it lives | What it is |
|---|---|---|
| Receipt JSON | Off-chain (returned to the buyer) | 8 fields describing the job: prompt_hash, response_hash, model, prompt_tokens, completion_tokens, wallclock_ms, supplier_pkh, escrow_ref |
| Signature | Off-chain, attached to the receipt | Ed25519 signature over the canonicalized receipt JSON, made with the same key that is the supplier's on-chain wallet identity |
| On-chain commitment | Escrow datum, permanent | sha256(canonical({receipt, signature})) - 32 bytes written by the supplier-signed Submit transaction and enforced by the validator |
Canonicalization is a JCS-style form: sorted keys, NFC strings, no whitespace.
What lands on-chain, step by step¶
- Post - the buyer locks payment + both bonds at the escrow script with an
Opendatum that already commits to the request:prompt_hash(hash of the full messages array) andrequest_spec_hash(capability, model, output cap). - Claim - the supplier signs on, before the delivery deadline.
- Submit - the supplier writes
result_receipt_hashinto the datum. The validator enforces the hash's presence and length, and stampssubmitted_atfrom the transaction's validity bound. The supplier's verification key is in the witness set - this is what makes the commitment attributable. - Accept - the buyer's signed transaction spends the escrow: supplier receives payment + supplier bond, buyer recovers the buyer bond. There is a 10-minute acceptance window.
- Release - if the buyer does nothing within the window, the supplier can settle unilaterally.
The durable on-chain record is the transaction pair: the Submit tx (supplier attestation: hash, timestamp, witness key) and the settlement tx (value released to each side; the buyer's witness when settled by Accept).
Store the receipt JSON
The chain holds only the 32-byte commitment. The receipt itself is returned to whoever ran the buyer side - the gateway includes it in every response's x_vector extension but does not persist it. If the JSON is discarded, an external party can later verify only that a commitment exists, and nothing else.
Verification recipe¶
Given a {receipt, signature} JSON, verify against public infrastructure. (Settled escrows are spent UTxOs - use a chain indexer or explorer for history; the marketplace indexer serves decoded escrow states, and anyone can self-host it.)
- Walk the lineage.
receipt.escrow_refnames the original Open UTxO. Follow the spends: Open → Claim → Submit → settlement, every hop at the escrow script address (addr1wxqsaczee4upnn50n9dwgw9mkph77yqp0d9p0y5ul9c6jysrv9dl5). - Decode the Submitted datum (14-field inline Plutus datum; field 12 is the receipt hash, field 5 the prompt hash).
- Recompute the commitment:
sha256(canonical({receipt, signature}))must equal datum field 12 and the Submit redeemer payload. - Verify the signature: take the verification key from the Submit transaction's witness set whose blake2b-224 equals the datum's
supplier_pkh, and check the Ed25519 signature overcanonical(receipt). This chains receipt → supplier key → on-chain identity → the key that moved the escrow. - Verify the content (requires the payloads): recompute
response_hashfrom the response andprompt_hashfrom the request messages; the prompt hash must also match what the buyer committed in the datum before the work happened. - Verify the settlement: the settlement transaction releases ≥ price + supplier bond to the supplier's credential (and returns the buyer bond on the Accept path).
What verification proves - and what it doesn't¶
Proves: integrity (this exact request produced this exact response), attribution (this registered supplier key signed it and moved the escrow), settlement (value moved under the committed terms, on-chain, timestamped).
Does not prove:
- Quality - hashes attest what was delivered, never whether it was good. Contested work goes to the Dispute Resolution module.
- Self-reported metrics -
prompt_tokens,completion_tokens, andwallclock_msare supplier-reported billing metadata, not validated on-chain. - Buyer counter-signature - the receipt is supplier-signed; the buyer's approval is the Accept transaction itself, and on the timeout Release path settlement completes without a buyer signature.
- Content of discarded receipts - no JSON, no content verification (see the warning above).
Where to get receipts¶
| Source | What you get |
|---|---|
| Gateway responses | x_vector: {receipt, receipt_signature, escrow_ref} on every completion - store it |
| Self-hosted buyer app | Full archive: receipt JSON, signature, and the exact request/response bytes |
| Marketplace indexer | Decoded escrow states and receipt hashes (never the JSON) |