Skip to content

How SubEtha uses x402 v2: request, payment, settlement

SubEtha carries a zERC20 payment (a privacy-oriented burn-and-mint payment) inside the official x402 v2 protocol — the envelope and headers are unmodified x402 v2, and everything SubEtha-specific rides inside the standard extension points (PaymentRequirements.extra and PaymentPayload.payload). If you’re new to SubEtha, Start here gives the five-minute model: the payer burns tokens to a one-time address, and the provider is paid later through a proof-gated mint. No direct on-chain record exposes a payer-to-provider link; the amount, timing, and anonymity-set limits of that property are covered in Privacy: what SubEtha hides — and what stays public. For the exact fields and message formats sent between the payer, provider, and facilitator, see the wire protocol reference.

party role
Payer (an AI agent or script) requests the resource and pays; sees a one-time burn address — the 402 does not disclose the provider’s payout destination
Provider (resource server) serves the HTTP resource behind a paywall; uses the official x402 middleware with the SubEtha scheme plugin
Facilitator trusted intermediary that sees every payment; derives the one-time burn addresses, verifies and settles payments, and later drives finalization; the only component that touches the chain-side settlement machinery

SubEtha registers the scheme subetha-zerc20 and uses x402 v2’s three headers exactly as the official protocol defines them. The PaymentRequired envelope carried by PAYMENT-REQUIRED contains one or more PaymentRequirements offers:

header direction contents
PAYMENT-REQUIRED 402 response → client base64 JSON PaymentRequired (the envelope of offers)
PAYMENT-SIGNATURE paying request → server base64 JSON PaymentPayload (the payment)
PAYMENT-RESPONSE served response → client base64 JSON SettleResponse (the settlement result)

SubEtha does not provide an x402 v1 (X-PAYMENT) fallback. Clients without a subetha-zerc20 handler skip SubEtha offers gracefully via standard x402 scheme filtering — advertising the scheme cannot break foreign clients.

  1. Request, unpaid. The payer requests the resource with no payment headers.
  2. HTTP 402 with an offer. The provider answers 402 Payment Required. The PAYMENT-REQUIRED header carries a PaymentRequired envelope whose PaymentRequirements offer specifies the scheme, the CAIP-2 network (eip155:<chainId>), the token contract (asset), the quoted amount in base units, a one-time burn address as payTo (freshly derived for every 402, never reused), maxTimeoutSeconds, and SubEtha’s extra block (challenge nonce, absolute expiry, optional gasless helper and deadline, optional fee disclosure). The provider cannot construct or issue this offer itself: only the facilitator can derive a burn address, so the scheme plugin fetches a fresh challenge from the facilitator per 402.
  3. The payment. The payer re-sends the request with PAYMENT-SIGNATURE carrying the full x402 v2 envelope: x402Version: 2, the selected subetha-zerc20 offer echoed verbatim in the x402 accepted field, and one of two payload shapes — the gasless permit (the payer signs a permit, which travels to the facilitator inside the paying request via the provider; the facilitator broadcasts the burn and pays its gas) or the self-transfer fallback (the payer broadcasts the burn transfer itself and includes the transaction hash). This x402 field name is unrelated to the accepted settlement phase below.
  4. Verify, serve, settle. The provider-side middleware verifies the payment through the facilitator (a read-only check), runs the resource handler with the response buffered, then settles. On the gasless path, settlement may trigger the facilitator’s burn broadcast; on either path it confirms that the burn landed on-chain. On success the buffered resource is released with a PAYMENT-RESPONSE header. If settlement fails, the buffered response is discarded and the client receives a 402 — nothing is served on a failed settle.

A zERC20 payment settles in two phases, and the two words are never interchangeable. x402 requires a synchronous payment decision before serving, while zERC20’s privacy construction depends on a time gap between the burn and the proof-gated mint. SubEtha therefore serves on the burn (accepted) and mints later (finalized). For the full explanation of the gap, see Accepted vs finalized.

phase when meaning
accepted synchronously, inside the HTTP request the burn transfer to the one-time payTo address has a successful receipt on-chain (indexed transfer, balance). The resource may be served on that receipt evidence; the separate reorg/finality risk is re-checked before finalization (see Accepted vs finalized)
finalized asynchronously, minutes later, never on the request path the proof-gated mint to the real recipient lands on-chain

Mapping onto x402: the facilitator’s /settle success == accepted. The mint stays out-of-band, driven by the facilitator’s finalize loop. A SettleResponse therefore carries extra: { phase: "accepted" }, and its transaction field is the burn transaction hash (the on-chain event a payer can audit) — not the mint.

What this construction hides is the correspondence between payer and provider on-chain — no direct on-chain record exposes which burn funded which mint; amounts are public. The full model, its caveats, and its limits are in Privacy: what SubEtha hides — and what stays public.

  • Offers carry an absolute expiry. A client must obtain a fresh 402 rather than reuse an old offer, and every 402 carries a new burn address.
  • Verification is point-in-time, not a settlement guarantee: on the gasless path, a payer can move its balance between verify and settle, in which case settle fails after the handler ran but before anything is served (the middleware replaces the buffered response with a 402). The funds themselves are never at risk for the provider; ordinary rate limiting covers the wasted compute.
  • On the gasless path, if the burn is still unmined when settlement answers, the facilitator responds { success: false, errorReason: "pending_burn" }; re-sending the same payload is idempotent and safe (the burn is never double-executed).