Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion x402/facilitator.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ never configure the facilitator at all; they discover it implicitly from the sel
// POST /verify and POST /settle request
{
"x402Version": 2,
"paymentPayload": { /* the decoded X-PAYMENT payload the buyer signed */ },
"paymentPayload": { /* the decoded payment payload the buyer signed */ },
"paymentRequirements": { /* the matching accept from the 402 */ }
}
```
Expand Down Expand Up @@ -136,6 +136,13 @@ When a seller offers an `upto` route, the SDK surfaces the `facilitatorAddress`
`eip2612GasSponsoring` extension in the `402` challenge automatically, and a compatible buyer signs
the gasless approval path with no extra configuration.

:::note
Gasless `upto` requires the **seller** to declare the EIP-2612 extension on the route
(`declareEip2612GasSponsoringExtension()`). Without it the facilitator can't sponsor the buyer's
Permit2 approval, and a 0-ETH buyer is rejected with `permit2_allowance_required` — see
[Quickstart: Sellers → Accepting `upto` and gasless payments](./quickstart-sellers.mdx#accepting-upto-and-gasless-payments).
:::

## Self-hosting

HPP's facilitator is a deployment of the standard open-source x402 facilitator, so you are not locked
Expand Down
27 changes: 15 additions & 12 deletions x402/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ until a valid payment is attached.
When an unpaid request arrives, it replies with `402` and a list of acceptable payment terms
(`accepts`). When a paid request arrives, it verifies and settles the payment, then returns the resource.
- **Client (the buyer).** A browser, a backend, or an AI agent that wants the resource. It reads the
`402`, signs a stablecoin authorization for one of the offered terms, and retries with an `X-PAYMENT` header.
`402`, signs a stablecoin authorization for one of the offered terms, and retries with a `payment-signature` header.
- **Facilitator.** A service that the resource server delegates two jobs to: **verify** a payment
signature, and **settle** it onchain. HPP operates the facilitators so sellers never run an RPC node
or hold a settlement key. See [Facilitator](./facilitator.mdx).
Expand All @@ -39,7 +39,7 @@ until a valid payment is attached.
│ (EIP-3009 / Permit2) │ │
│ │ │
│ 4. GET /paid/resource │ │
X-PAYMENT: <signed payload> │ │
payment-signature: <signed> │ │
│ ───────────────────────────────► │ 5. verify(payload) │
│ │ ──────────────────────────────► │
│ │ ◄────────────────────────────── │
Expand All @@ -48,13 +48,13 @@ until a valid payment is attached.
│ │ ──────────────────────────────► │ ──► onchain tx
│ │ ◄────────────────────────────── │
│ 8. 200 OK + resource │ │
X-PAYMENT-RESPONSE: <receipt>│ │
payment-response: <receipt> │ │
│ ◄─────────────────────────────── │ │
```

HPP's resource-server middleware uses **serve-then-settle**: it verifies the payment first, serves the
response, and settles after a successful result (`status < 400`). The buyer gets a settlement receipt
back in the `X-PAYMENT-RESPONSE` header.
back in the `payment-response` header.

## The 402 challenge

Expand Down Expand Up @@ -87,7 +87,7 @@ The body of the `402` response (x402 version 2) tells the buyer exactly how it m
- `extra` carries the EIP-712 domain the buyer needs to sign (`exact`), and scheme-specific data such
as the `facilitatorAddress` for gas-sponsored `upto`.
- A multi-network or multi-scheme seller returns several `accepts`; the buyer's SDK selects one (next
section). The settlement receipt comes back base64-encoded in the `X-PAYMENT-RESPONSE` header and
section). The settlement receipt comes back base64-encoded in the `payment-response` header and
decodes to `{ success, transaction, network, payer, amount? }`.

## Payment schemes
Expand All @@ -99,26 +99,29 @@ HPP supports two upstream-standard schemes:
### `exact`

Pay an **exact** amount using [EIP-3009](https://eips.ethereum.org/EIPS/eip-3009)
(`transferWithAuthorization`). The buyer signs a transfer for the precise price; the facilitator
submits it. Simple and final — best when the price is known up front.
(`transferWithAuthorization`). The buyer only signs a transfer for the precise price; the facilitator
submits it onchain and pays the gas, so the buyer needs no ETH. Simple and final — best when the price
is known up front.

### `upto`

Authorize **up to** a maximum using [Permit2](https://github.com/Uniswap/permit2), and settle the
actual amount consumed (which may be less than the cap). This fits metered or usage-based pricing
where the final cost isn't known until the work runs.

On HPP, `upto` also supports **gasless settlement**: the one-time Permit2 approval can be sponsored
via [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612), so a paying agent needs **zero native ETH** —
only USDC.e. See [Facilitator → Gasless settlement](./facilitator.mdx#gasless-settlement-upto).
Like `exact`, the settlement itself is relayed by the facilitator. The one extra cost is `upto`'s
**one-time Permit2 approval** — and on HPP that approval is sponsored via
[EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) **when the seller enables it**, so a paying agent
needs **zero native ETH**, only USDC.e. See
[Facilitator → Gasless settlement](./facilitator.mdx#gasless-settlement-upto).

> Both schemes are part of the standard x402 specification. A facilitator advertises exactly which
> `(network, scheme)` pairs it supports at its `/supported` endpoint, and the seller's accepts must be
> a subset of that.

Each payment authorization is **single-use**: it carries a unique nonce and a validity window, so a
captured `X-PAYMENT` header cannot be replayed for a second charge, and the buyer signs a fresh
authorization for every request.
captured `payment-signature` header cannot be replayed for a second charge, and the buyer signs a
fresh authorization for every request.

## Next

Expand Down
8 changes: 5 additions & 3 deletions x402/networks-and-token.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,15 @@ Because USDC.e has **6 decimals**, prices in the x402 `accepts` are expressed as

## Funding

Because every payment is denominated in **USDC.e**, a buyer needs a USDC.e balance before it can pay
ETH alone only covers gas (and `upto` can be made gasless, needing no ETH at all).
Because every payment is denominated in **USDC.e**, a buyer needs a USDC.e balance before it can pay.
The facilitator submits the settlement transaction and pays the gas, so a **buyer normally needs no ETH**.

- **Gas (ETH).** On testnet, get HPP Sepolia ETH from the [HPP Sepolia Faucet](https://faucet.hpp.io/).
- **USDC.e.** USDC.e is Bridged USDC. Bring it onto HPP by bridging from the parent chain — see the
[Bridge guide](/community/bridge). For testnet USDC.e to run the quickstarts, reach out through
[Official Links](/community/official-links).
- **ETH (rarely needed).** Only a buyer paying `upto` against a seller *without* EIP-2612 sponsoring
needs a little ETH, for the one-time Permit2 approval. Get testnet ETH from the
[HPP Sepolia Faucet](https://faucet.hpp.io/). Sellers/operators also need ETH to deploy contracts.

Verify a balance any time on the [block explorer](https://explorer.hpp.io/) (mainnet) or
[Sepolia explorer](https://sepolia-explorer.hpp.io/) by looking up the USDC.e contract above.
25 changes: 14 additions & 11 deletions x402/quickstart-buyers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ USDC.e authorization with your wallet, and retries automatically — your code j

- A wallet (private key) holding **USDC.e** on the target network — payments are denominated in USDC.e,
not ETH. See [Networks & Token → Funding](./networks-and-token.mdx#funding) for how to acquire it.
- For the **`exact`** scheme, the wallet also needs a little **ETH** for gas.
- For **`upto`**, the buyer normally needs a one-time Permit2 approval. On HPP this approval can be
gas-sponsored via EIP-2612, so a wallet with **only USDC.e and zero ETH** can pay — see
[Facilitator → Gasless settlement](./facilitator.mdx#gasless-settlement-upto).
- The facilitator submits the settlement transaction and pays the gas, so the buyer **does not need ETH**:
- **`exact`** — the buyer only signs an EIP-3009 authorization; the facilitator relays it. Zero ETH.
- **`upto`** — also relayed, but it needs a one-time Permit2 approval. On HPP that approval is
gas-sponsored via EIP-2612 when the seller enables it, so the buyer still needs **zero ETH** (see
[Facilitator → Gasless settlement](./facilitator.mdx#gasless-settlement-upto)). Only against a seller
or chain *without* sponsoring does the buyer pay a little ETH for that first approval.

:::caution
Use a dedicated test wallet on **HPP Sepolia** while integrating. Never hard-code a mainnet private
Expand All @@ -36,8 +38,8 @@ npm install @x402/core @x402/evm @x402/fetch viem
## 2. Wrap fetch with payment

Build a scheme client backed by your wallet, hand it to an `x402Client`, and wrap `fetch`. The buyer
needs **USDC.e** to pay; for `exact` it also needs a little ETH for gas, while `upto` can be made
[gasless](./facilitator.mdx#gasless-settlement-upto).
needs **USDC.e** to pay; the facilitator submits settlement and pays the gas, so the buyer needs no
ETH for `exact` and — with seller-enabled sponsoring — none for [`upto`](./facilitator.mdx#gasless-settlement-upto) either.

<Tabs>
<TabItem value="mainnet" label="HPP Mainnet">
Expand Down Expand Up @@ -151,12 +153,13 @@ console.log(res.status); // 200
console.log(await res.json()); // the resource

// Onchain settlement receipt, if the server returned one.
const header = res.headers.get("x-payment-response");
const header = res.headers.get("payment-response");
if (header) {
const receipt = decodePaymentResponseHeader(header);
// { success, transaction, network, payer, amount?, ... }
console.log("settled tx:", receipt.transaction, "on", receipt.network);
// For `upto`, `receipt.amount` is the ACTUAL amount charged (≤ the authorized max).
// `receipt.amount`, when present, is the actual amount charged — for `upto`
// this can be less than the authorized maximum.
}
```

Expand Down Expand Up @@ -199,9 +202,9 @@ The verify/settle decision happens on the resource server via the facilitator; t
/ `SettleError` are raised *there*, not on the buyer — see
[Facilitator → Verify and settle](./facilitator.mdx#verify-and-settle).

> **Use the SDK client to encode payments.** The `X-PAYMENT` header has a specific encoding that the
> resource-server middleware validates. Hand-rolling the header will be rejected — always pay through
> `wrapFetchWithPayment` (or the MCP/agent wrappers built on the same client).
> **Use the SDK client to encode payments.** The `payment-signature` header has a specific encoding
> that the resource-server middleware validates. Hand-rolling the header will be rejected — always pay
> through `wrapFetchWithPayment` (or the MCP/agent wrappers built on the same client).

## Agents and MCP

Expand Down
37 changes: 31 additions & 6 deletions x402/quickstart-sellers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ the SDK supports.
## 1. Install

```bash
npm install @x402/express @x402/core @x402/evm express
npm install @x402/express @x402/core @x402/evm @x402/extensions express
```

## 2. Register USDC.e
Expand Down Expand Up @@ -124,13 +124,38 @@ app.listen(4021, () => console.log("x402 resource server on :4021"));
```

That's it. An unpaid `POST /paid/hello` now returns `402` with your terms; a request carrying a valid
`X-PAYMENT` header is verified, served, and settled onchain — and the handler returns the resource.
`payment-signature` header is verified, served, and settled onchain — and the handler returns the resource.

## Accepting both schemes
## Accepting `upto` and gasless payments

To offer `exact` and `upto` on the same route, list both in `accepts` (priority order — the buyer's
SDK picks the first it supports) and register both schemes on the network. `upto` routes can also
advertise gasless settlement; see [Facilitator → Gasless settlement](./facilitator.mdx#gasless-settlement-upto).
To also accept the `upto` scheme, list it in the route's `accepts` (in priority order — the buyer's
SDK picks the first it supports) and register it on the network alongside `exact`.

For **gasless `upto`** — letting a buyer with **zero native ETH** pay — the route must declare the
**EIP-2612 gas-sponsoring extension**. Without it, the facilitator cannot sponsor the buyer's Permit2
approval, and a buyer without a standing allowance is rejected with `permit2_allowance_required`.

```ts
import { declareEip2612GasSponsoringExtension } from "@x402/extensions";

// Replaces the route from step 4. `PAY_TO` and the `price` object are the same
// as before (here `price` is the { amount, asset, extra } object shown above).
const routes: RoutesConfig = {
"POST /paid/hello": {
description: "A paid hello-world endpoint.",
accepts: [
{ scheme: "exact", network: "eip155:190415", payTo: PAY_TO, price, maxTimeoutSeconds: 600 },
{ scheme: "upto", network: "eip155:190415", payTo: PAY_TO, price, maxTimeoutSeconds: 600 },
],
// Required for gasless `upto`: lets the facilitator sponsor the buyer's
// one-time Permit2 approval via EIP-2612 (so a 0-ETH wallet can pay).
extensions: { ...declareEip2612GasSponsoringExtension() },
},
};
```

The facilitator must advertise `eip2612GasSponsoring` for the network (HPP Mainnet and Sepolia both
do — see [Facilitator → Gasless settlement](./facilitator.mdx#gasless-settlement-upto)).

## Next

Expand Down
1 change: 1 addition & 0 deletions x402/sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ recognizes Base, Polygon, and other EVM chains.
| `@x402/core` | both | `x402Client`, `HTTPFacilitatorClient`, `RoutesConfig` types. |
| `@x402/evm` | both | EVM scheme clients (`exact`, `upto`) and the `DEFAULT_STABLECOINS` asset map. |
| `@x402/express` | sellers | `paymentMiddleware` and `x402ResourceServer` for Express. |
| `@x402/extensions` | sellers | Route extensions, e.g. `declareEip2612GasSponsoringExtension()` for gasless `upto`. |
| `@x402/fetch` | buyers | `wrapFetchWithPayment` to make a paying `fetch`. |
| `viem` | buyers | Wallet account and chain utilities (`privateKeyToAccount`, `defineChain`). |

Expand Down