Architecture: three parties and one HTTP boundary
SubEtha’s runtime is three parties talking over plain HTTP, plus the local zERC20 stack that only one of them ever touches. This page maps the parties, the HTTP surfaces between them, and the trust boundaries — who holds which keys and who can do what. The wire format itself is the wire protocol reference; the lifecycle semantics are x402 v2 on SubEtha and Accepted vs finalized.
The three parties
Section titled “The three parties”payer (AI agent / script) │ x402 v2 over HTTP: request → 402 offer → paying request → resource ▼provider (resource server, official x402 middleware + SubEtha scheme plugin) │ facilitator HTTP API: /supported /challenge /verify /settle ▼facilitator (settlement daemon) │ RPC + indexer + prover — the only party that touches the chain ▼local zERC20 stack (anvil, deployed contracts, indexer, decider) → treasury- The payer requests the resource and pays. It sees only what the 402
offer shows it: token, network, quoted amount, expiry, and a one-time burn
address as
payTo. It is never shown the provider’s real payout destination. - The provider serves the HTTP resource behind a paywall. It runs the official x402 middleware with the SubEtha scheme plugin and delegates every payment question to the facilitator.
- The facilitator derives the one-time burn addresses, verifies and settles payments, and later drives finalization (the proof-gated mint). It is the only component that talks to the chain, the indexer, or the prover.
The HTTP boundary
Section titled “The HTTP boundary”Everything between parties is HTTP — there is no shared database, queue, or SDK linkage across party lines.
Payer ↔ provider is unmodified x402 v2: the PAYMENT-REQUIRED header on
the 402 response (the offer), PAYMENT-SIGNATURE on the paying request (the
payment), and PAYMENT-RESPONSE on the served response (the settlement
result). SubEtha adds no headers and provides no x402 v1 fallback.
Provider ↔ facilitator is the standard x402 facilitator API plus one SubEtha extension:
| endpoint | why the provider calls it |
|---|---|
GET /supported |
at initialization — the middleware hard-fails unless the facilitator advertises the subetha-zerc20 kind |
POST /challenge |
per unpaid 402 — a burn address can only be derived by the facilitator, so a provider cannot mint its own offer the way vanilla x402 sellers do |
POST /verify |
on a paying request — a read-only, point-in-time check |
POST /settle |
after the resource handler ran — executes the burn-confirmation path; success means accepted |
The facilitator treats the requirements echoed in these calls as untrusted and compares them against its own challenge record, rejecting any mismatch.
Trust boundaries: who holds what
Section titled “Trust boundaries: who holds what”| party | holds | can |
|---|---|---|
| payer | its own EOA key | sign or broadcast a burn to the offered payTo; nothing else |
| provider | no keys in the shipped configuration — not even a payout EOA’s | serve or withhold the resource; it never touches the chain or the zERC20 SDK |
| facilitator | SUBETHA_TREASURY_PK, SUBETHA_RELAYER_PK, the burn-address derivation seed, optional SUBETHA_ADMIN_TOKEN |
derive offers, broadcast permit burns, submit proof-gated mints, sweep fees |
Three consequences of that split:
- The payout destination lives facilitator-side. The provider’s route config carries no payout address or secret; the treasury (or the FeeSplit contract) is named in the facilitator’s configuration. A compromised provider process therefore leaks no settlement keys.
- The BUSL boundary is confined to the facilitator. All use of
@zerc20/sdk(BUSL-1.1) and its Node/wasm specifics lives inside the facilitator’s settlement backend. Payer and provider integrate through Apache-2.0 packages and plain HTTP. - The facilitator is fully trusted for settlement. It sees every payment, derives every burn address, and controls when finalization runs. What that trust means in practice — and what failure looks like at each boundary — is Trust & Limits.
The chain-side machinery
Section titled “The chain-side machinery”The facilitator settles against the official zERC20 stack running locally:
anvil as the chain, the deployed official contracts, the indexer, and the
decider/prover. That stack is a prerequisite the product repository documents
(build it per
docs/BUILDING-THE-STACK.md,
run it per
docs/RUNNING-THE-STACK.md);
it is not vendored into SubEtha and not documented further on this site.
One SubEtha-authored contract participates: PermitBurner (Apache-2.0), the
helper that makes the gasless permit path atomic — it grants the allowance
from the payer’s EIP-2612 signature and executes the burn transfer in a
single transaction.