Skip to content
Spec/Wire Format
v0.12.6stableReleases

Wire Format Specification

PEAC receipts are JWS (JSON Web Signature) compact serializations with Ed25519 signatures. Two record formats coexist: peac-receipt/0.1 (frozen legacy) and interaction-record+jwt (Interaction Record Format 0.2, stable).

v0.12.6

Versioning Doctrine

The repository version (0.12.6) is decoupled from the wire format versions. Two wire formats coexist: Wire 0.1 (peac-receipt/0.1) for flat receipt records and Wire 0.2 (interaction-record+jwt) for structured kinds with typed extensions. Both formats use Ed25519 signatures and the PEAC-Receipt header. verifyLocal() auto-detects wire version.

Wire Format Identifiers

Wire 0.1 (Stable)

Type (typ)

peac-receipt/0.1

Algorithm (alg)

EdDSA

Key Type (crv)

Ed25519

Current Key ID (kid)

peac-2026-03

Wire 0.2 (Stable)

Type (typ)

interaction-record+jwt

Algorithm (alg)

EdDSA

Key Type (crv)

Ed25519

Structural Kinds

evidence | challenge
Wire 0.2 adds structured kinds (evidence/challenge), open semantic type (reverse-DNS or URI), multi-valued pillars, 12 typed extension groups, and policy binding (JCS + SHA-256).

JWS 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...

The protected header contains algorithm and type information:

ClaimValueRequiredDescription
typpeac-receipt/0.1 or interaction-record+jwtYesWire format type identifier (determines Wire 0.1 or 0.2)
algEdDSAYesSignature algorithm (Ed25519 only)
kidpeac-YYYY-MMYesKey ID for JWKS lookup

Wire 0.1 Payload Claims

Wire 0.1 (peac-receipt/0.1) uses flat payload claims:

ClaimTypeRequiredDescription
issstringYesIssuer (HTTPS URL)
audstringYesAudience (recipient domain)
iatnumberYesIssued at (Unix timestamp)
amtnumberNoAmount
curstringNoCurrency code (ISO 4217)
railstringNoPayment rail (x402, stripe, card, razorpay)
referencestringNoSettlement reference
subjectstringNoResource subject (URL)

Wire 0.2 Payload Claims (Stable)

Wire 0.2 (interaction-record+jwt) introduces structured kinds, typed extensions, and policy binding:

ClaimTypeRequiredDescription
issstringYesIssuer (canonical: https:// or did: only)
iatnumberYesIssued at (Unix timestamp)
peac_versionstringYesMust be "0.2"
kindstringYesStructural kind: "evidence" or "challenge"
typestringYesSemantic type (reverse-DNS or absolute URI)
pillarsstring[]NoVerification domains (sorted, unique, from 10-pillar taxonomy)
extensionsobjectNoTyped extension groups (keyed by reverse-DNS)
policyobjectNoPolicy binding (uri, version, digest as sha256:hex)
occurred_atstringNoISO 8601 event time (evidence kind only)
actorobjectNoActor binding (identity proof)
representationobjectNoContent representation fields (content_hash, content_type, content_length)

Wire 0.2 Extension Groups

Wire 0.2 defines 12 typed extension groups. Extensions are keyed by reverse-DNS (org.peacprotocol/*) and validated with strict schemas:

KeyFieldsDescription
org.peacprotocol/commercepayment_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/accessresource, action, decision (allow/deny/review)Access control decisions
org.peacprotocol/challengechallenge_type (7 values), problem (RFC 9457)Challenge requirements
org.peacprotocol/identityproof_ref?Identity attestation
org.peacprotocol/correlationtrace_id?, span_id?, workflow_id?, parent_jti?, depends_on?Multi-step workflow correlation
org.peacprotocol/consentbasis, scope, granted_at?, expires_at?, withdrawable?Consent records
org.peacprotocol/privacydata_categories?, retention?, legal_basis?Privacy and data handling evidence
org.peacprotocol/safetymodel?, guardrails?, risk_level?AI safety and guardrail evidence
org.peacprotocol/complianceframework?, controls?, assessment?Regulatory compliance evidence
org.peacprotocol/provenancesource?, transformations?, lineage?Data and content provenance
org.peacprotocol/attributioncreator?, license?, attribution_text?Content attribution and licensing
org.peacprotocol/purposedeclared_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.

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

Wire 0.1 Receipt Payload

{
  "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"
}

Wire 0.2 Evidence Receipt Payload

{
  "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..."
  }
}

Wire 0.2 Challenge Receipt Payload

{
  "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
      }
    }
  }
}

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:

  1. Parse the JWS compact serialization
  2. Decode and validate the protected header
  3. Detect wire version from typ: peac-receipt/0.1 (Wire 0.1) or interaction-record+jwt (Wire 0.2)
  4. Verify alg is EdDSA
  5. Reject embedded keys (jwk, x5c, x5u, jku), crit, b64: false, and zip
  6. Verify Ed25519 signature over header.payload
  7. Validate payload claims per wire version
  8. Wire 0.2: validate policy binding (3-state: verified/failed/unavailable)