Skip to content
Spec/Wire Format

Wire Format Specification

The PEAC receipt wire format is a JWS (JSON Web Signature) compact serialization with Ed25519 signatures. Wire format peac-receipt/0.1 is FROZEN.

v0.10.13FROZEN

Versioning Doctrine

The repository version (0.10.13) is decoupled from the wire format version (peac-receipt/0.1). Wire format peac-receipt/0.1 is FROZEN until v1.0. New features are added via extension claims, not breaking changes to the core format.

Wire Format Identifier

Type (typ)

peac-receipt/0.1

Algorithm (alg)

EdDSA

Key Type (crv)

Ed25519

Current Key ID (kid)

peac-2026-02

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.1YesWire format type identifier
algEdDSAYesSignature algorithm (Ed25519 only)
kidpeac-YYYY-MMYesKey ID for JWKS lookup

Payload Claims

The payload contains the receipt data:

ClaimTypeRequiredDescription
ridstringYesReceipt ID (ULID format)
iatnumberYesIssued at (Unix timestamp)
expnumberYesExpiration time (Unix timestamp)
issstringYesIssuer (HTTPS URL)
audstringYesAudience (recipient domain)
substringNoSubject identifier
paymentobjectNoPayment details (rail, amount, currency)
controlobjectNoControl decision details
purpose_*anyNoPurpose-specific extension claims

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 Receipt

A complete example of a PEAC receipt payload:

{
  "rid": "01JQXF8N7K4P2R3S5T6V7W8X9Y",
  "iat": 1706659200,
  "exp": 1706662800,
  "iss": "https://payment.example.com",
  "aud": "api.consumer.com",
  "sub": "agent:openai-gpt4",
  "payment": {
    "rail": "x402",
    "amount": "0.05",
    "currency": "USD",
    "tx_hash": "0x1234...abcd"
  },
  "control": {
    "decision": "allow",
    "purposes": ["inference"],
    "policy_version": "peac-policy/0.1"
  }
}

HTTP Transport

Receipts are transmitted via the PEAC-Receipt HTTP header as a detached JWS compact serialization:

# 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. Verify typ is peac-receipt/0.1
  4. Verify alg is EdDSA
  5. Fetch JWKS from issuer's /.well-known/jwks.json
  6. Find key matching kid in JWKS
  7. Verify Ed25519 signature over header.payload
  8. Validate payload claims (iat, exp, iss, aud)