<!-- Generated raw Markdown for /concepts/x402-v2; product pin 638fa1e9ca7face19a442cef43754f0d627c7705. -->

SubEtha is a **local, non-production proof of concept**. It carries a zERC20
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`).
This page explains the request/payment/settlement lifecycle conceptually; the
normative field-by-field wire format is the
[wire protocol reference](/reference/protocol/).

## The three parties

| party | role |
|---|---|
| **Payer** (an AI agent or script) | requests the resource and pays; sees only a one-time burn address, never the provider's real payout destination |
| **Provider** (resource server) | serves the HTTP resource behind a paywall; uses the official x402 middleware with the SubEtha scheme plugin |
| **Facilitator** | derives the one-time burn addresses, verifies and settles payments, and later drives finalization; the only component that touches the chain-side settlement machinery |

## The envelope: unmodified x402 v2

SubEtha registers the scheme **`subetha-zerc20`** and uses x402 v2's three
headers exactly as the official protocol defines them:

| header | direction | contents |
|---|---|---|
| `PAYMENT-REQUIRED` | 402 response → client | base64 JSON `PaymentRequired` (the offer) |
| `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 on this surface.
Clients without a `subetha-zerc20` handler skip SubEtha offers gracefully via
standard x402 scheme filtering — advertising the scheme cannot break foreign
clients.

## The lifecycle

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 `PaymentRequirements`: 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 mint
   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 received offer
   echoed **verbatim** as `accepted`, and one of two payload shapes —
   the **gasless permit** (the payer only signs; 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).
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. Settlement executes the
   burn-confirmation path; 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**.

## `accepted` is not `finalized`

A zERC20 payment settles in **two phases**, and the two words are never
interchangeable:

| phase | when | meaning |
|---|---|---|
| **accepted** | synchronously, inside the HTTP request | the burn transfer to the one-time `payTo` address is confirmed on-chain (receipt success, indexed transfer, balance). The resource MAY be served: the funds are already burned and the payer cannot reclaim them |
| **finalized** | asynchronously, minutes later, never on the request path | the proof-gated mint to the real recipient lands on-chain |

Mapping onto x402: **`/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**; amounts are public. The full model, its caveats, and its
limits are in the product repository's
[overview](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/docs/OVERVIEW.md)
until this site's concepts pages land.

## Offers expire; failures fail closed

- 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: 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).

## Where to go next

- [Wire protocol reference](/reference/protocol/) — normative field-by-field
  format, EIP-712 definitions, facilitator HTTP API.
- [Configuration reference](/reference/configuration/) — facilitator config
  keys and payer environment variables.
- [TypeScript API](/reference/typescript/) and [Python API](/reference/python/)
  — the published client/provider surfaces.
- [Versions & compatibility](/reference/compatibility/) — protocol scope,
  package versions, and license boundaries.
