Skip to content

Protocol specification 1.0.0

Six primitives, one economic interaction.

Everything in EPP-402 revolves around six standardised objects. Each has a JSON Schema generated from the implementation's own definitions, a TypeScript type, and, where it is signed, an EIP-712 struct bound to the settlement chain. The tables below are read from those definitions at build time.

Lifecycle

Discovery → Quote → Session → Intent → Settlement → Receipt

Four stages happen before money moves and are pure signed data. Settlement is the single on-chain step, executed by an x402 facilitator. The receipt is issued after delivery, so a settled payment and a fulfilled service stay distinct facts.

01 · Discovery

Discovery

A provider publishes what it sells, the assets it accepts, the facilitators it settles through and the key its quotes and receipts are signed with. The registry indexes the document; it is never required to buy.

On the wire

GET /.well-known/epp402.json

schemaDiscoveryDocument
11 fields
FieldMeaning
protocol"epp-402"—
version"1.0.0"—
provider{ id, name, address, payTo, url, description, contact, verification }Who the provider is and which key speaks for it.
networkstringCAIP-2 identifier of an EVM network (eip155:<chainId>).
networksstring[] · optional—
assetsobject[]—
x402{ version, schemes, facilitators }—
servicesobject[]—
receipts{ signer, verifyEndpoint } · optional—
updatedAtintegerInteger Unix timestamp in seconds (UTC).
signaturestring · optional65-byte secp256k1 signature (r, s, v), 0x-prefixed.

Served at /.well-known/epp402.json. Optionally attested with an EIP-712 DiscoveryAttestation over the document's canonical hash.

02 · Quote

Quote

Deterministic, time-bound pricing signed by the provider's key. Once the agent accepts it, the amount cannot move: the 402 must price the resource at exactly the quoted amount.

On the wire

POST /v1/quotes → signed Quote

schemaQuote
18 fields
FieldMeaning
protocol"epp-402"—
version"1.0.0"—
quoteIdstringEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
provider{ id, address }—
serviceIdstringService identifier, unique within the provider.
paramsobject—
paramsHashstring32-byte 0x-prefixed hex value.
quantityinteger · optional—
price{ amount, asset, decimals, symbol, network }—
payTostringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
buyerstring · optionalEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
sessionIdstring · optionalEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
issuedAtintegerInteger Unix timestamp in seconds (UTC).
expiresAtintegerInteger Unix timestamp in seconds (UTC).
noncestring32-byte 0x-prefixed hex value.
conditions{ maxExecutionSeconds, deliverable, refundable, notes } · optional—
x402{ scheme, network, asset, amount, payTo, maxTimeoutSeconds, extra }—
signaturestring65-byte secp256k1 signature (r, s, v), 0x-prefixed.

Signed by the provider's key (EIP-712 Quote). The x402 block is what the 402 must advertise, field for field.

03 · Commerce session

Commerce session

The coordination object for one workflow, which may span several providers. It holds the spending limit, every quote, every authorization, what settled and what was delivered. Partial execution is a state, not an error.

On the wire

ses_… · created → quoted → authorized

schemaSession
17 fields
FieldMeaning
protocol"epp-402"—
version"1.0.0"—
sessionIdstringEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
buyer{ address, agent }—
status"created" | "quoted" | "authorized" | "executing" | "settled" | "completed" | "partially_settled" | "expired" | "failed" | "cancelled"—
networkstringCAIP-2 identifier of an EVM network (eip155:<chainId>).
assetstringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
spendingLimitstringUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
authorizedstringUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
spentstringUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
providersstring[]—
itemsobject[]—
createdAtintegerInteger Unix timestamp in seconds (UTC).
updatedAtintegerInteger Unix timestamp in seconds (UTC).
expiresAtintegerInteger Unix timestamp in seconds (UTC).
historyobject[]—
metadataobject · optional—

Off-chain state kept by the buyer's SDK or a hosted session service, published to the registry with the buyer's attestation.

04 · Payment intent

Payment intent

The agent's authorization of one payment, under its spending policy: payer, recipient, exact amount, window and the nonce the token will burn, so an intent can settle at most once.

On the wire

EIP-712 by the payer · bound to the EIP-3009 nonce

schemaPaymentIntent
20 fields
FieldMeaning
protocol"epp-402"—
version"1.0.0"—
intentIdstringEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
sessionIdstring · optionalEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
quoteIdstringEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
payerstringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
recipientstringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
assetstringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
networkstringCAIP-2 identifier of an EVM network (eip155:<chainId>).
amountstringUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
ceilingstring · optionalUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
validAfterintegerInteger Unix timestamp in seconds (UTC).
validBeforeintegerInteger Unix timestamp in seconds (UTC).
noncestring32-byte 0x-prefixed hex value.
scheme"exact"—
status"created" | "signed" | "submitted" | "settled" | "failed" | "expired" | "cancelled"—
createdAtintegerInteger Unix timestamp in seconds (UTC).
updatedAtintegerInteger Unix timestamp in seconds (UTC).
signaturestring · optional65-byte secp256k1 signature (r, s, v), 0x-prefixed.
execution{ txHash, settlementId, submittedAt, settledAt, error } · optional—

Signed by the payer (EIP-712 PaymentIntent). Its nonce is the EIP-3009 nonce the token burns on settlement, so an intent settles at most once.

05 · Settlement

Settlement

The facilitator verifies the signed authorization against the requirements, broadcasts it on Elysium and waits for the receipt. The payer never pays gas and the facilitator never holds funds.

On the wire

PAYMENT-SIGNATURE → facilitator → Elysium

schemaSettlement
24 fields
FieldMeaning
protocol"epp-402"—
version"1.0.0"—
settlementIdstringEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
networkstringCAIP-2 identifier of an EVM network (eip155:<chainId>).
scheme"exact"—
assetstringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
amountstringUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
payerstringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
payTostringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
noncestring · optional32-byte 0x-prefixed hex value.
txHashstring32-byte 0x-prefixed hex value.
blockNumberinteger · optional—
status"pending" | "confirmed" | "failed"—
confirmationsinteger · optional—
facilitatorstring · optionalEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
relaystring · optionalEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
quoteIdstring · optionalEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
intentIdstring · optionalEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
sessionIdstring · optionalEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
receiptIdstring · optionalEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
resourcestring · optional—
submittedAtintegerInteger Unix timestamp in seconds (UTC).
confirmedAtinteger · optionalInteger Unix timestamp in seconds (UTC).
error{ code, message } · optional—

Recorded by the facilitator. Only `confirmed` is proof of payment, and payment is not proof of delivery.

06 · Receipt

Receipt

The provider's signed statement that this payment bought this service and whether it was delivered. Anyone can verify it: recover the signature, read the transaction, compare the transfer.

On the wire

EPP-RECEIPT · EIP-712 by the provider

schemaReceipt
17 fields
FieldMeaning
protocol"epp-402"—
version"1.0.0"—
receiptIdstringEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
sessionIdstring · optionalEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
intentIdstring · optionalEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
quoteIdstringEPP-402 object identifier: a short type prefix, an underscore and 26 Crockford base32 characters.
payerstringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
provider{ id, address }—
service{ id, resource, resultHash }—
amountstringUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
assetstringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
networkstringCAIP-2 identifier of an EVM network (eip155:<chainId>).
txHashstring32-byte 0x-prefixed hex value.
settledAtintegerInteger Unix timestamp in seconds (UTC).
fulfillment{ status, deliveredAt, detail }—
issuedAtintegerInteger Unix timestamp in seconds (UTC).
signaturestring65-byte secp256k1 signature (r, s, v), 0x-prefixed.

Signed by the provider (EIP-712 Receipt). The fulfillment status is inside the signed struct.

Session state machine

Partial execution is a state, not an exception.

Every allowed transition, as the implementation enforces it. Terminal states accept nothing. A multi-provider session is never represented as an atomic transaction; the manager tracks what settled, what failed and what still needs compensation.

FromCan move toTerminal
CreatedquotedcancelledexpiredNo
QuotedquotedauthorizedcancelledexpiredNo
AuthorizedauthorizedquotedexecutingcancelledexpiredNo
Executingexecutingsettledpartially_settledfailedNo
Partially settledpartially_settledexecutingsettledcompletedfailedNo
Settledpartially_settledcompletedfailedNo
Completed—Yes
Expired—Yes
Failed—Yes
Cancelled—Yes
Signatures

Four signed structs, one domain, bound to the chain.

Domain EPP-402, version 1, with the chain id of the settlement network, so a quote or receipt signed for one network cannot be replayed as another's. Identifiers travel as keccak256 of their string form; a zero hash means none.

Quote

  • quoteIdbytes32
  • provideraddress
  • serviceIdbytes32
  • paramsHashbytes32
  • amountuint256
  • assetaddress
  • chainIduint256
  • payToaddress
  • buyeraddress
  • sessionIdbytes32
  • issuedAtuint64
  • expiresAtuint64
  • noncebytes32

PaymentIntent

  • intentIdbytes32
  • sessionIdbytes32
  • quoteIdbytes32
  • payeraddress
  • recipientaddress
  • assetaddress
  • chainIduint256
  • amountuint256
  • validAfteruint64
  • validBeforeuint64
  • noncebytes32

Receipt

  • receiptIdbytes32
  • sessionIdbytes32
  • intentIdbytes32
  • quoteIdbytes32
  • payeraddress
  • provideraddress
  • assetaddress
  • chainIduint256
  • amountuint256
  • txHashbytes32
  • settledAtuint64
  • serviceIdbytes32
  • resultHashbytes32
  • fulfillmentuint8
  • issuedAtuint64

DiscoveryAttestation

  • providerIdbytes32
  • provideraddress
  • documentHashbytes32
  • updatedAtuint64

SessionAttestation

  • sessionIdbytes32
  • buyeraddress
  • documentHashbytes32
  • updatedAtuint64
The seam with x402

Commerce references ride in the one place x402 reserves for them.

A quote's x402 block is exactly what the 402 must advertise. The quote, session and intent identifiers travel under extensions.epp402 and are echoed back by the client, so the facilitator and the explorer can tie a settlement to a session without any change to the x402 wire format.

schemaSpendingPolicy
11 fields
FieldMeaning
version"1.0.0"—
namestring · optional—
networkstringCAIP-2 identifier of an EVM network (eip155:<chainId>).
assetstringEVM address, 0x-prefixed, 40 hex characters. Compare case-insensitively.
maxPerTransactionstring · optionalUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
maxPerSessionstring · optionalUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
maxPerDaystring · optionalUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).
allowedProvidersstring | string[] · optional—
allowedAssetsobject[] · optional—
authorizationTtlSecondsinteger · optional—
approvalThresholdstring · optionalUnsigned integer amount in the asset's minor units, as a decimal string (BigInt-safe).

Evaluated by the SDK before it signs. An off-chain policy restricts what the SDK will sign; wallet-level limits are recommended wherever the wallet supports them.

PAYMENT-REQUIRED (decoded)Illustrative
{
  "x402Version": 2,
  "resource": {
    "url": "https://inference.example.com/v1/inference",
    "description": "Standard inference",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:99801",
      "asset": "0x…EPPUSD",
      "amount": "10000",
      "payTo": "0xb1297Fea0b54A79BdBCfb8b057e39B226Cc2ebFc",
      "maxTimeoutSeconds": 300,
      "extra": {
        "name": "EPP-402 Test USD",
        "version": "1"
      }
    }
  ],
  "extensions": {
    "epp402": {
      "info": {
        "version": "1.0.0",
        "providerId": "inference.example.com",
        "quoteId": "qt_01k9r3w6zj8e2n0h4yv7c5b9ma"
      }
    }
  }
}
Versioning

Semantic versions, frozen only after interoperability tests.

Every object carries its schema version. The core wire format is not frozen before interoperability tests are complete; once finalised, backward compatibility is maintained under semantic versioning.

SpecificationVersion
EPP-402 Core1.0.0
Discovery schema1.0.0
Quote schema1.0.0
Session schema1.0.0
Intent schema1.0.0
Settlement schema1.0.0
Receipt schema1.0.0
Elysium adapter1.0.0
x402 compatibilityv2