> ## Documentation Index
> Fetch the complete documentation index at: https://docs.algovoi.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Payment Evidence Frame (PEF)

> AlgoVoi authored canonical wrapper format for payment lifecycle receipts: a byte deterministic frame_id via JCS RFC 8785 plus optional RFC 9421 signature.

The Payment Evidence Frame (PEF) is a transport-agnostic envelope that wraps any AlgoVoi payment-lifecycle receipt into a single, verifiable artefact. Each frame carries a byte-deterministic `frame_id` (SHA-256 of the JCS-canonical preimage) and an optional detached RFC 9421 signature field.

It is AlgoVoi-authored, specified in IETF Internet-Draft [`draft-hopley-x402-payment-evidence-frame-00`](https://datatracker.ietf.org/doc/draft-hopley-x402-payment-evidence-frame/) (published 2026-05-30, Independent Submission), and published as a standalone reference implementation:

* Python: [`algovoi-pef`](https://pypi.org/project/algovoi-pef/) (live, v0.1.0)
* TypeScript: [`@algovoi/pef`](https://www.npmjs.com/package/@algovoi/pef) (live, v0.1.0)

Both packages depend on [`algovoi-substrate`](https://pypi.org/project/algovoi-substrate/) / [`@algovoi/substrate`](https://www.npmjs.com/package/@algovoi/substrate) for the JCS canonicalisation primitive. Apache 2.0.

## Lifecycle position

PEF is the outermost envelope. It wraps every receipt type in the payment lifecycle stack:

```
compliance   --> settlement  --> cancellation --> refund
receipt           attestation      receipt         receipt
    |                  |               |              |
    +------------------+---------------+--------------+
                       |
                  payment_evidence_frame
                  (frame_id, claim_type,
                   receipt_hash, signature)
```

All five wrapped formats anchor to the same canonicalisation discipline ([`urn:x402:canonicalisation:jcs-rfc8785-v1`](https://datatracker.ietf.org/doc/draft-hopley-x402-canonicalisation-jcs-v1/)). A verifier holding a PEF can independently re-derive `frame_id` from the enclosed receipt without trusting the issuer's assertion.

## Why this format

Downstream consumers of payment evidence -- auditors, regulators, acquiring counterparties -- receive receipts from multiple sources in multiple formats. PEF answers three problems:

* **Canonical identity**: `frame_id` is a SHA-256 of the JCS-canonical preimage. Any party can recompute it offline. There is no proprietary identifier or opaque token to trust.
* **Uniform verification surface**: a single verifier handles all five receipt types without format-specific parsing logic. The `claim_type` field is the sole discriminator.
* **Optional signature binding**: RFC 9421 HTTP Message Signatures attach a detached signature to the frame bytes, binding the issuer's keypair to the canonical `frame_id`. The frame is fully verifiable without the signature; the signature narrows the trust surface for regulated contexts.

## Frame shape

A PEF frame is a six-field JSON object canonicalised under RFC 8785 (JCS):

```json theme={null}
{
  "canon_version": "urn:x402:canonicalisation:jcs-rfc8785-v1",
  "claim_type": "payment_admission",
  "frame_id": "sha256:09929082c83d5006f61f06bb12eb58cc2c21acebd70a31bca3cb26169c11b6bf",
  "frame_provider_did": "did:web:api.algovoi.co.uk",
  "frame_timestamp_ms": 1748534600000,
  "receipt_hash": "sha256:abc123..."
}
```

| Field                | Type                 | Description                                                                     |
| -------------------- | -------------------- | ------------------------------------------------------------------------------- |
| `canon_version`      | string               | In-band canonicalisation pin. Fixed `urn:x402:canonicalisation:jcs-rfc8785-v1`. |
| `claim_type`         | string (closed enum) | Receipt type discriminator. See table below.                                    |
| `frame_id`           | string               | `sha256:{hex}` -- SHA-256 of the JCS-canonical preimage bytes. Self-describing. |
| `frame_provider_did` | string               | DID URI of the party asserting the frame.                                       |
| `frame_timestamp_ms` | integer              | Epoch milliseconds. **Substrate Rule 2**.                                       |
| `receipt_hash`       | string               | `sha256:{hex}` -- SHA-256 of the JCS-canonical receipt bytes.                   |

The optional `signature` field carries a detached RFC 9421 / RFC 9530 Content-Digest over the canonical frame bytes. Its presence is indicated by the `sig` key; its absence does not invalidate the frame.

## Claim types

Five claim types, each mapping to an IETF I-D-anchored receipt format:

| `claim_type`           | Receipt format                                                                                  | IETF I-D                                                                                                                 |
| ---------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `payment_admission`    | Compliance receipt (ALLOW / REFER / DENY)                                                       | [`draft-hopley-x402-compliance-receipt`](https://datatracker.ietf.org/doc/draft-hopley-x402-compliance-receipt/)         |
| `payment_settlement`   | Settlement attestation (SETTLED / PENDING\_FINALITY / REVERSED)                                 | [`draft-hopley-x402-settlement-attestation`](https://datatracker.ietf.org/doc/draft-hopley-x402-settlement-attestation/) |
| `payment_cancellation` | Cancellation receipt (USER\_REQUESTED / MERCHANT\_REQUESTED / COMPLIANCE\_TERMINATED / EXPIRED) | [`draft-hopley-x402-cancellation-receipt`](https://datatracker.ietf.org/doc/draft-hopley-x402-cancellation-receipt/)     |
| `payment_refund`       | Refund receipt (FULL / PARTIAL / REJECTED)                                                      | [`draft-hopley-x402-refund-receipt`](https://datatracker.ietf.org/doc/draft-hopley-x402-refund-receipt/)                 |
| `composite_verdict`    | Composite trust-query response (TRUSTED / PROVISIONAL / INSUFFICIENT\_EVIDENCE / UNTRUSTED)     | [`draft-hopley-x402-composite-trust-query`](https://datatracker.ietf.org/doc/draft-hopley-x402-composite-trust-query/)   |

## `frame_id` derivation

```
preimage = JCS(
  canon_version,
  claim_type,
  frame_provider_did,
  frame_timestamp_ms,
  receipt_hash
)
frame_id = "sha256:" + hex(SHA-256(preimage))
```

`frame_id` is excluded from the JCS preimage -- standard JCS self-describing identifier pattern. Any verifier with the receipt bytes can recompute `receipt_hash`, recompute `preimage`, and independently verify `frame_id` without trusting the issuer.

## Cross-implementation validation

`frame_id` derivation has been independently validated across **eight JCS implementations in eight programming languages** -- **64/64 byte-for-byte agreements** across all five claim types (both `receipt_hash` and `frame_id` layers per vector):

| Language   | JCS library                                                                 |
| ---------- | --------------------------------------------------------------------------- |
| Python     | `rfc8785` 0.1.4 (Trail of Bits)                                             |
| JavaScript | `canonicalize` 1.0.8 (Samuel Erdtman)                                       |
| Ruby       | `json-canonicalization` 1.0.0                                               |
| PHP        | inline pure-stdlib JCS (AlgoVoi)                                            |
| Go         | `gowebpki/jcs` v1.0.1 (Web PKI Working Group)                               |
| Rust       | `serde_jcs` 0.2.0                                                           |
| Java       | `erdtman/java-json-canonicalization` 1.1 (Anders Rundgren + Samuel Erdtman) |
| .NET       | `Baqhub.Packages.JsonCanonicalization` 1.0.1                                |

Full attestation record: [`_attestations/2026-05-30-8-impl-pef-v1.md`](https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors/blob/main/_attestations/2026-05-30-8-impl-pef-v1.md) in [`chopmob-cloud/algovoi-jcs-conformance-vectors`](https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors).

The cumulative cross-validation corpus now stands at **880/880 byte-for-byte agreements** across fourteen vector sets covering the full AlgoVoi agentic-payment receipt stack (as of 2026-06-18).

## Quick start

### Python

```python theme={null}
from algovoi_pef import build_pef, verify_pef

frame = build_pef(
    claim_type="payment_admission",
    receipt={
        "canon_version": "urn:x402:canonicalisation:jcs-rfc8785-v1",
        "jurisdiction_flags": ["EU", "UK"],
        "payer_ref": "sha256:abc123...",
        "prev_hash": None,
        "screen_provider_did": "did:web:api.algovoi.co.uk",
        "screen_result": "ALLOW",
        "screen_timestamp_ms": 1748534600000,
    },
    frame_provider_did="did:web:api.algovoi.co.uk",
    frame_timestamp_ms=1748534600000,
)

result = verify_pef(frame)
assert result["valid"]
print(frame["frame_id"])
# sha256:09929082c83d5006f61f06bb12eb58cc2c21acebd70a31bca3cb26169c11b6bf
```

### TypeScript

```typescript theme={null}
import { buildPef, verifyPef } from "@algovoi/pef";

const frame = buildPef({
  claim_type: "payment_settlement",
  receipt: {
    canon_version: "urn:x402:canonicalisation:jcs-rfc8785-v1",
    settled_payment_ref: "sha256:abc123...",
    settlement_chain: "ethereum:84532",
    settlement_provider_did: "did:web:api.algovoi.co.uk",
    settlement_result: "SETTLED",
    settlement_timestamp_ms: 1748534700000,
  },
  frame_provider_did: "did:web:api.algovoi.co.uk",
  frame_timestamp_ms: 1748534700000,
});

const result = verifyPef(frame);
console.log(result.valid);    // true
console.log(frame.frame_id);  // sha256:...
```

### Platform integration

The platform wraps receipts automatically via `pef_or_none()` -- returns `None` if `algovoi-pef` is not installed, so existing API responses are unaffected during a rolling deploy:

```python theme={null}
from shared.utils.pef_wrapper import wrap_compliance_receipt

pef_frame = wrap_compliance_receipt(
    compliance_receipt_dict,
    screen_timestamp_ms=screen_ts,
)
```

## What this is NOT

* **Not a receipt format itself.** PEF is a wrapper. The enclosed receipt retains its own canonical identity (`receipt_hash`) and IETF I-D normative status.
* **Not a cryptographic settlement proof.** PEF records the operator's categorical claim. Cryptographic proofs of payment conditions are orthogonal and compose on top.
* **Not a transport protocol.** PEF is a JSON envelope. How it is transmitted (HTTP response header, webhook payload, audit-log row) is out of scope.

## Companion IETF Internet-Draft

[`draft-hopley-x402-payment-evidence-frame-00`](https://datatracker.ietf.org/doc/draft-hopley-x402-payment-evidence-frame/) (Independent Submission, published 2026-05-30). AlgoVoi-authored, sole authorship. Normatively references [`draft-hopley-x402-canonicalisation-jcs-v1`](https://datatracker.ietf.org/doc/draft-hopley-x402-canonicalisation-jcs-v1/) and all five receipt-format I-Ds.

## See also

* [Canonicalisation substrate](/canonicalisation-substrate) -- the JCS discipline
* [Compliance gate](/compliance-gate-v1) -- admission-time receipt (payment\_admission)
* [Settlement attestation](/settlement-attestation) -- post-settlement receipt (payment\_settlement)
* [Cancellation receipt](/cancellation-receipt) -- mandate termination (payment\_cancellation)
* [Refund receipt](/refund-receipt) -- post-settlement refund (payment\_refund)
* [Composite trust query](/composite-trust-query) -- multi-issuer verdict (composite\_verdict)
* [Conformance vectors](/conformance-vectors) -- full vector corpus
* [Substrate authorship and provenance](/substrate-authorship-provenance) -- citable AlgoVoi authorship record
