Skip to main content
The cancellation receipt records that a recurring-payment mandate (or any standing payer→payee authorisation) has been cancelled, by whom, for what reason, and with what effective date. It closes the lifecycle gap between recurring execution (settlement attestations) and post-cancellation refund (where owed). It is AlgoVoi-authored, specified in IETF Internet-Draft draft-hopley-x402-cancellation-receipt (POSTED on IETF datatracker 2026-05-25, Independent Submission, Informational), and published as a standalone reference implementation:
  • Python: algovoi-cancellation-receipt (live on PyPI, v0.1.1)
Both packages depend on algovoi-substrate / @algovoi/substrate for the JCS canonicalisation primitive. Apache 2.0.

Lifecycle position

All four formats anchor to the same canonicalisation discipline (urn:x402:canonicalisation:jcs-rfc8785-v1). A verifier walking the audit chain confirms admission → recurring execution → termination → (optional) refund under one byte-deterministic pin.

Why a four-state enumeration

Mandate termination is genuinely four-state. The regulatorily-load-bearing distinctions are:
  • Payer revocation under PSD2 (Directive 2015/2366) Article 64 + UK Consumer Rights Act 2015 — MAY trigger refund obligations on debits already settled prior to the effective date.
  • Payee termination under PSD2 Article 72 + contractual terms — does NOT trigger consumer-revocation refund-window obligations on already-settled debits.
  • Operator/compliance-forced termination (sanctions, KYC, AML, court order) — anchors POCA s.330 / AML 5+6 evidence chain back to the originating compliance event.
  • Time-based expiry — mandate’s own terms terminated it. Standard record-keeping only.
A collapse to three-state (e.g. PARTY_REQUESTED + AUTO_TERMINATED) loses the payer-vs-payee distinction that drives the PSD2 Article 64 refund-window obligation.

Receipt shape

A cancellation receipt is a seven-field JSON object canonicalised under RFC 8785 (JCS). Field names are sorted lexicographically by JCS during canonicalisation.

The closed enumeration: cancellation_reason

Each value produces a byte-distinct content_hash. Free-form “reason” strings or operator-internal codes are not acceptable substitutes.

Two timestamps

The cancellation receipt records two epoch-millisecond integer timestamps independently:
  • cancellation_timestamp_ms — when the cancellation event was observed and recorded by the issuing provider.
  • effective_from_ms — when the cancellation takes legal effect.
For most cancellations these are equal. For PSD2 Article 64(3)(a) direct-debit revocations, the effective time is typically end-of-business-day prior to the next scheduled execution — distinct from the moment the revocation was recorded. The independent encoding supports that operational separation. The format pins the invariant effective_from_ms >= cancellation_timestamp_ms. Implementations MUST reject receipts where the effective time precedes the recording time.

Composition

A cancellation receipt mandate_ref MAY reference a compliance receipt content_hash (the receipt that admitted the mandate). A USER_REQUESTED cancellation may chain forward to a refund receipt if PSD2 Article 64 refund is owed on a recently-settled debit:
A verifier walking this chain confirms the full mandate lifecycle under one canonicalisation pin.

Conformance vectors

8 byte-level reference vectors + 7 pair invariants + 3 chain invariants at vectors/cancellation_receipt_v1/. The vector set pins:
  1. Closed four-element cancellation_reason enumeration — four byte-distinct content_hash values.
  2. jurisdiction_flags array order (RFC 8785 §3.2.3).
  3. canon_version in-band pin.
  4. effective_from_ms >= cancellation_timestamp_ms invariant.
  5. mandate_ref content-addressing (sha256: prefix retained in canonical bytes).
  6. Audit chain row linkage via prev_hash.

Quick start

TypeScript

What this is NOT

  • Not a refund receipt. Cancellation records the termination of a mandate; refund records the reversal of a settled payment. When a USER_REQUESTED cancellation triggers a refund, both receipts are emitted and chained via the audit-chain.
  • Not a dispute receipt. Disputes are state machines over multiple parties; cancellation is a single state transition.
  • Not an attestation of mandate validity. The receipt records the termination of a previously-valid mandate; the mandate itself is specified elsewhere.

Companion IETF Internet-Draft

draft-hopley-x402-cancellation-receipt (Independent Submission, Informational). AlgoVoi-authored. Normatively references draft-hopley-x402-canonicalisation-jcs-v1. Welcomes downstream-adopter contributions per the established Appendix C “Known Adopters” pattern.

See also