Wire Format Specification
PEAC receipts are JWS (JSON Web Signature) compact serializations with Ed25519 signatures. The current stable format is interaction-record+jwt (Interaction Record format), with structured kinds, typed extensions, and policy binding.
Versioning Doctrine
The repository version (0.12.11) is decoupled from the wire format version. The current stable format is the Interaction Record format (interaction-record+jwt) for structured kinds with typed extensions. The legacy Wire 0.1 (peac-receipt/0.1) format is frozen and accepted only for backward compatibility. Both formats use Ed25519 signatures and the PEAC-Receipt header. verifyLocal() auto-detects wire version.
Wire Format Identifiers
Interaction Record Format (Current)
Type (typ)
interaction-record+jwtAlgorithm (alg)
EdDSAKey Type (crv)
Ed25519Structural Kinds
evidence | challengeevidence/challenge), open semantic type (reverse-DNS or URI), multi-valued pillars, 12 typed extension groups, and policy binding (JCS + SHA-256). This is the recommended format for all new integrations.Wire 0.1 (Frozen Legacy)
Type (typ)
peac-receipt/0.1Algorithm (alg)
EdDSAKey Type (crv)
Ed25519Current Key ID (kid)
peac-2026-03JWS Structure
PEAC receipts are encoded as JWS Compact Serialization (RFC 7515) with three base64url-encoded parts separated by periods:
BASE64URL(header).BASE64URL(payload).BASE64URL(signature) // Example receipt structure: eyJ0eXAiOiJwZWFjLXJlY2VpcHQvMC4xIiwiYWxnIjoiRWREU0EiLCJraWQiOiJwZWFjLTIwMjYtMDEifQ. eyJyaWQiOiIwMUpRWEY4...
Protected Header
The protected header contains algorithm and type information:
| Claim | Value | Required | Description |
|---|---|---|---|
typ | interaction-record+jwt | Yes | Wire format type identifier. Legacy peac-receipt/0.1 also accepted for backward compatibility. |
alg | EdDSA | Yes | Signature algorithm (Ed25519 only) |
kid | peac-YYYY-MM | Yes | Key ID for JWKS lookup |
Payload Claims (Interaction Record format)
The current stable format (interaction-record+jwt) uses structured kinds, typed extensions, and policy binding:
| Claim | Type | Required | Description |
|---|---|---|---|
iss | string | Yes | Issuer (canonical: https:// or did: only) |
iat | number | Yes | Issued at (Unix timestamp) |
peac_version | string | Yes | Must be "0.2" |
kind | string | Yes | Structural kind: "evidence" or "challenge" |
type | string | Yes | Semantic type (reverse-DNS or absolute URI) |
pillars | string[] | No | Verification domains (sorted, unique, from 10-pillar taxonomy) |
extensions | object | No | Typed extension groups (keyed by reverse-DNS) |
policy | object | No | Policy binding (uri, version, digest as sha256:hex) |
occurred_at | string | No | ISO 8601 event time (evidence kind only) |
actor | object | No | Actor binding (identity proof) |
representation | object | No | Content representation fields (content_hash, content_type, content_length) |
Extension Groups
The Interaction Record format defines 12 typed extension groups. Extensions are keyed by reverse-DNS (org.peacprotocol/*) and validated with strict schemas:
| Key | Fields | Description |
|---|---|---|
org.peacprotocol/commerce | payment_rail, amount_minor (string), currency, event? (6-value enum), reference?, asset?, env?, payment_state_source? | Commerce and payment evidence. The event field is observational metadata only and does not encode settlement finality. |
org.peacprotocol/access | resource, action, decision (allow/deny/review) | Access control decisions |
org.peacprotocol/challenge | challenge_type (7 values), problem (RFC 9457) | Challenge requirements |
org.peacprotocol/identity | proof_ref? | Identity attestation |
org.peacprotocol/correlation | trace_id?, span_id?, workflow_id?, parent_jti?, depends_on? | Multi-step workflow correlation |
org.peacprotocol/consent | basis, scope, granted_at?, expires_at?, withdrawable? | Consent records |
org.peacprotocol/privacy | data_categories?, retention?, legal_basis? | Privacy and data handling evidence |
org.peacprotocol/safety | model?, guardrails?, risk_level? | AI safety and guardrail evidence |
org.peacprotocol/compliance | framework?, controls?, assessment? | Regulatory compliance evidence |
org.peacprotocol/provenance | source?, transformations?, lineage? | Data and content provenance |
org.peacprotocol/attribution | creator?, license?, attribution_text? | Content attribution and licensing |
org.peacprotocol/purpose | declared_purpose?, permitted_purposes?, restrictions? | Purpose limitation and use constraints |
Registered first-party evidence types require their mapped extension group in strict mode. Interop mode downgrades missing extensions to warnings. Challenge-kind and custom types are exempt. Unknown-but-well-formed extension keys are preserved with a warning. Malformed keys produce a hard error.
Wire 0.1 Payload Claims (Frozen Legacy)
Wire 0.1 (peac-receipt/0.1) is the frozen legacy format. It uses flat payload claims and is maintained only for backward compatibility:
| Claim | Type | Required | Description |
|---|---|---|---|
iss | string | Yes | Issuer (HTTPS URL) |
aud | string | Yes | Audience (recipient domain) |
iat | number | Yes | Issued at (Unix timestamp) |
amt | number | No | Amount |
cur | string | No | Currency code (ISO 4217) |
rail | string | No | Payment rail (x402, stripe, card, razorpay) |
reference | string | No | Settlement reference |
subject | string | No | Resource subject (URL) |
Content Hash Format
Content hashes follow a specific format for interoperability:
// Format: algorithm:hex_value "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" // Requirements: // - Algorithm: sha256 (only supported algorithm) // - Value: 64 lowercase hexadecimal characters // - Total length: 71 characters (sha256: + 64 hex chars)
Example Receipts
Evidence Receipt Payload (Interaction Record format)
{
"iss": "https://api.example.com",
"iat": 1709500000,
"peac_version": "0.2",
"kind": "evidence",
"type": "org.peacprotocol/payment",
"pillars": ["commerce"],
"extensions": {
"org.peacprotocol/commerce": {
"payment_rail": "x402",
"amount_minor": "10000",
"currency": "USD",
"event": "authorization"
}
},
"policy": {
"uri": "https://api.example.com/.well-known/peac.txt",
"version": "peac-policy/0.1",
"digest": "sha256:a1b2c3..."
}
}Challenge Receipt Payload (Interaction Record format)
{
"iss": "https://api.example.com",
"iat": 1709500000,
"peac_version": "0.2",
"kind": "challenge",
"type": "org.peacprotocol/payment",
"extensions": {
"org.peacprotocol/challenge": {
"challenge_type": "payment_required",
"problem": {
"type": "https://www.peacprotocol.org/problems/payment-required",
"title": "Payment Required",
"status": 402
}
}
}
}Wire 0.1 Receipt Payload (Frozen Legacy)
{
"iss": "https://api.example.com",
"aud": "https://client.example.com",
"iat": 1709500000,
"amt": 100,
"cur": "USD",
"rail": "x402",
"reference": "tx_abc123",
"subject": "https://api.example.com/inference"
}HTTP Transport
Receipts are transmitted via the PEAC-Receipt HTTP header as a compact JWS:
# Request with receipt GET /api/resource HTTP/1.1 Host: api.example.com PEAC-Receipt: eyJhbGciOiJFZERTQSIsInR5cCI6InBlYWMtcmVjZWlwdC8wLjEiLCJraWQiOiJwZWFjLTIwMjYtMDEifQ.eyJyaWQiOiIwMUpRWEY4... # The header contains the complete JWS: # - Protected header (base64url) # - Payload (base64url) # - Signature (base64url)
Verification Process
Receipt verification follows these steps:
- Parse the JWS compact serialization
- Decode and validate the protected header
- Detect wire version from
typ:peac-receipt/0.1(Wire 0.1) orinteraction-record+jwt(current) - Verify
algisEdDSA - Reject embedded keys (
jwk,x5c,x5u,jku),crit,b64: false, andzip - Verify Ed25519 signature over
header.payload - Validate payload claims per wire version
- Interaction Record format: validate policy binding (3-state: verified/failed/unavailable)