
402 Payment Required status code. A server answers an unpaid request with a 402 and a machine-readable payment requirement; the client signs a payment authorization and retries; a facilitator verifies the signature and settles it on-chain. The protocol is chain-agnostic, with requirements keyed by CAIP-2 network IDs such as eip155:91342, and is governed by the x402 Foundation under the Linux Foundation, initiated by Coinbase.
Two EVM schemes matter here:
exact: settle one fixed amount. With an ERC-3009 asset, the facilitator callstransferWithAuthorizationdirectly on the token.upto: authorize a signed maximum, settle the actual measured amount. In x402-rs this scheme is Permit2-only, signing aPermitWitnessTransferFromfor a fixed Upto proxy address, because an ERC-3009 authorization fixes its amount at signing time.
Why self-hosted on GIWA
GIWA does not officially support x402, and Coinbase’s hosted facilitator does not list GIWA. Tokscale ported the stack and answered the hardest open question, whether x402 works on GIWA at all, on the public chain. Three pieces make it work:- Pinned self-hosted facilitator:
ghcr.io/x402-rs/x402-facilitator@sha256:89ab5c03…, mapped to x402-rs 2.0.2 revision0b14f39a. The image refused to start foreip155:91342until two hardcoded startup-check contracts existed on the chain, so Tokscale deployed them: the canonical Exact Permit2 Proxy and the ERC-6492 UniversalSigValidator, both at their canonical CREATE2 addresses. - Canonical Permit2 proxies:
uptohardcodes the Upto proxy address in x402-rs, so no substitute deployment is possible. Tokscale deployed the canonical Upto Permit2 Proxy from pinned upstream source and byte-verified it against the x402-rs constants. Permit2 itself (0x000000000022D473030F116dDEE9F6B43aC78BA3) is an OP Stack preinstall whose observed runtime hash matches the pinned rebuild. - An isolated adapter process: the workspace is on axum 0.7.9, while x402-rs 2.0.2 is built on axum 0.8, so linking it in would force a framework upgrade across every crate. Instead the adapter is a standalone process outside the workspace, hand-written against three dependencies (
base64,serde_json,sha2), and it speaks to the pinned facilitator image over HTTP. The gateway reaches it over a bearer-authenticated local JSON interface (POST /v1/verify,/v1/settle,/v1/recover). No x402-rs crate is linked anywhere in the repository and no x402-rs type crosses the seam, so the adapter is the only component that talks to the facilitator, the chain RPC, and the settlement journal.
The 402 flow
When a request arrives withx-giwa-payment-mode: x402 but no payment signature, the gateway fails closed to HTTP 402.
1
Quote a body-aware maximum
The gateway computes the maximum from the canonical request bounds and the sealed catalog price. The quote query is side-effect free: an
upto challenge never creates a payment intent before its authorization verifies.2
Return the 402 challenge
The response carries the quote and a freshly issued expiry of 60 seconds. A native 402 writes nothing durable.
3
Accept the signed retry
The client retries with a signed
PAYMENT-SIGNATURE header. The gateway rebinds to the originally issued expiry carried inside the signature, because recomputing from the wall clock would derive a different Permit2 nonce. Stale or extended expiries are rejected with a fresh 402 rather than silently repriced, and only then does the gateway verify through the adapter.4
Persist the authorization
Only after a successful verify does the gateway write the intent, outbox, and immutable payment authorization in one transaction.
Two stages, two schemes
The same ported stack carries both payment models, and they exist for different reasons:
The design rule shared by both: a token transfer is never treated as payment unless it matches an already persisted intent. ERC-3009 itself warns that a public
transferWithAuthorization can be front-run when an application needs a wrapper-specific action, so an ordinary transfer to the treasury credits nothing.
The full mechanics live on one page each: the intent state machine and the exactly-once credit rule in Stage A: Credit Top-Up, and the request binding, the settlement journal, and response-loss recovery in Stage B: Per-Request Settlement.
Public proof for Stage A (GIWA Sepolia, 2026-07-23): the pinned facilitator advertised exact for eip155:91342, rejected a mismatched chain, asset, and tampered signature at /verify, settled one 1.0 tUSD authorization (tx 0xad1a2f7b…fcb9f8), and rejected a replay of the same authorization with the ERC-3009 authorization-used selector.
Preventing a double settlement
Stage B is defended three times over, at three different layers, so no single failure can produce two payments:- On-chain: the Permit2 unordered nonce is derived from the request binding digest, so a second settle for the same request reverts against the nonce bitmap.
- In the adapter process: an append-only journal records a prepared entry before the sole settlement side effect. If a prepared entry exists without a transaction hash, the adapter refuses to broadcast again and recovers read-only instead.
- In the database: admission is idempotent, and finalize is fenced by both a lease and the transaction hash.
What the gateway stores
The gateway never holds a payer private key and never broadcasts. After a successful verify it stores only the admission record: intent and project IDs, request fingerprint, network, asset, treasury, payer, authorization nonce, maximum amount, the adapter’s payment commitment hash, and the opaque signed header. No prompt, completion, or key material. The adapter token renders as<redacted> in debug output, and presented API keys are redacted at the execution boundary.
Evidence
Two test-only overlays inject real failures into the sealed localnet. The first kills the reconciler after a real EIP-3009 settlement lands but before it observes the candidate, then force-recreates it. The proof is exactly one credit, exactly one canonical settlement, and a same-value ordinary transfer that was not credited:Next steps
- For the intent lifecycle and the exactly-once credit rule in full, see x402 Stage A: Credit Top-Up.
- For the request binding, settlement journal, and response-loss recovery, see x402 Stage B: Per-Request Settlement.
- For the addresses behind the ported stack, see The Public Chain.
- For what is proven publicly versus locally, see Live Evidence.