Skip to main content

Quickstart: Sellers

Put a price on an HTTP route and let HPP's facilitator handle verification and onchain settlement. This example uses the @x402/express middleware, but the same pieces apply to any HTTP framework the SDK supports.

1. Install

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

2. Register USDC.e

HPP's USDC.e is registered in the SDK's default-asset map so the exact (EIP-3009) domain (Bridged USDC / version 2 / 6 decimals) is filled in automatically. Run this once at startup, before constructing the resource server:

import { DEFAULT_STABLECOINS } from "@x402/evm";

const USDC_E = {
address: "0x401eCb1D350407f13ba348573E5630B83638E30D",
name: "Bridged USDC",
version: "2",
decimals: 6,
};
DEFAULT_STABLECOINS["eip155:190415"] = USDC_E; // HPP Mainnet
DEFAULT_STABLECOINS["eip155:181228"] = USDC_E; // HPP Sepolia

3. Build the resource server

Point a facilitator client at HPP's hosted facilitator and register the schemes you want to accept on each network.

import { x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { UptoEvmScheme } from "@x402/evm/upto/server";
import { HTTPFacilitatorClient } from "@x402/core/server";

const facilitator = new HTTPFacilitatorClient({ url: "https://facilitator.hpp.io" });

const resourceServer = new x402ResourceServer([facilitator]);
resourceServer.register("eip155:190415", new ExactEvmScheme());
resourceServer.register("eip155:190415", new UptoEvmScheme());

Only register what the facilitator supports. The resource server throws if you advertise a (network, scheme) pair that the facilitator does not return from /supported. exact and upto are supported on both HPP networks. You can pass multiple facilitator clients to x402ResourceServer([...]) to serve more than one network from a single process.

4. Price your routes and mount the middleware

Each route lists one or more accepts (one per (network, scheme)), priced in USDC.e base units.

import express from "express";
import { paymentMiddleware } from "@x402/express";
import type { RoutesConfig } from "@x402/core/server";

const PAY_TO = "0xYourReceivingAddress"; // where settled USDC.e lands

const routes: RoutesConfig = {
"POST /paid/hello": {
description: "A paid hello-world endpoint.",
accepts: [
{
scheme: "exact",
network: "eip155:190415",
payTo: PAY_TO,
price: {
amount: "10000", // 0.01 USDC.e (6 decimals)
asset: "0x401eCb1D350407f13ba348573E5630B83638E30D",
extra: { name: "Bridged USDC", version: "2" },
},
maxTimeoutSeconds: 600,
},
],
},
};

const app = express();
app.use(paymentMiddleware(routes, resourceServer));

app.post("/paid/hello", (_req, res) => {
res.json({ message: "Thanks for paying — here is your resource." });
});

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 payment-signature header is verified, served, and settled onchain — and the handler returns the resource.

Accepting upto and gasless payments

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.

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

Next