Verdict, not log
A log hands you what happened and leaves the conclusion to you. Two people reading the same lines can disagree about whether the payment settled, and a missing line looks identical to a line nobody thought to write. A receipt states the conclusion. For every milestone of the operation it says confirmed or not, points at the events behind that call, and names what is missing in plain language. Absence is a first-class part of the answer, not a gap in the output — so the receipt never quietly implies a milestone it did not observe. It is built from your own observations, not handed to you by the counterparty. That is what makes it usable when the two of you disagree.Templates and stages
A template describes an operation as an ordered sequence of milestone stages. It is scoped to what a single observer can witness: in the x402 flow each side gets its own template, since the buyer, the resource server, and the facilitator each see only their half. The buyer’s milestones arechallenge → payment → settlement; the seller’s, request → verification → settlement; the
facilitator’s, verification → settlement.
Each stage’s match is a match-set: any one of its events closes the stage.
That is deliberate — different clients witness the same milestone differently, so
the buyer’s payment milestone can be closed by a signed payment leaving an HTTP
client or by an MCP client initiating payment for a tool call:
role that has to have observed it. It is optional —
without it, any role closes the stage — and it matters wherever two roles share a
vocabulary: a resource server and a facilitator both record x402.verify.ok for
the same payment, so a seller’s receipt would otherwise be closed by the
facilitator’s witness, claiming something the run does not support.
Templates are data, not code — a new scenario is a new template file, never a
change to the assembler.
The verdict
1
Each stage gets a state
confirmed when at least one witness from its match-set was observed;
otherwise not_confirmed. A confirmed stage carries the event_ids of the
witnesses behind it — the evidence.2
Gaps are explained, never hidden
A required stage left unclosed is surfaced under
missing, each with a
plain-language explanation from the template’s missing_explanation.3
Faults surface as exceptions
An event whose type is in the template’s
exceptions (e.g.
x402.settle.failed) does not close a stage — it is recorded on the
operation as a fault.4
Completeness is decided
full only when every required stage is confirmed, at least one stage
closed, and no fault was observed. Otherwise partial.partial: a run that observed nothing is a gap, not a clean completion of
nothing.
One receipt per operation
Recording is per run — one start of your service, one recorder’s lifetime, one file of events; a session and a run are the same unit. A run usually holds many payments, interleaved. What separates them is thecontext_id
each event carries, set from the runtime context of the request it belongs to, so
a run splits into one receipt per operation.
Some events belong to no single operation — an attestation that capture attached,
or an out-of-band signal such as a chain confirmation arriving later. They are
kept aside rather than attributed to whichever payment was nearby. Guessing would
put evidence behind a verdict that never earned it.
Deterministic and reproducible
The assembler is a pure function — no model, no randomness, no clock. The same events and template always yield the same receipt, byte for byte. That has a practical consequence: the receipt is not a rendering of a run, it is a derivation from it. Keep the events and the template version, and anyone can rebuild the identical receipt and check it against yours. Feed the same events in a different order, or merge two capture sessions covering one payment, and the result does not change. Reproducibility is also why the template’sversion travels on the receipt.
Templates evolve; a verdict is only meaningful against the one that produced it.
The Receipt object
Every surface — terminal,receipt.json, markdown — renders the same object:
events is the full set the receipt was built from, in a deterministic order —
including events no stage matched. The receipt is self-contained provenance, so
what was seen and not used is visible too.
For an agent, completeness: "partial" plus missing: [settlement] is a
machine-readable basis to stop a chain of spending.
Next steps
Assemble one
Turn a run file into receipts with
haia-trace build.Write a template
Describe an operation of your own, stage by stage.
Record x402
Capture a payment’s lifecycle with one line.
Record Circle
Capture verified webhook v2 deliveries.