Public networks
Base Sepolia
Real USDC on a public testnet, through a remote facilitator, with no key in the gateway.
The same gateway as the local examples, settling real USDC on a public testnet. There is no different code path: a different network and a remote facilitator. The gateway holds no signing key.
version: 1
merchant:
id: base-sepolia-example
name: Base Sepolia Example
publicBaseUrl: ${GATEWAY_PUBLIC_BASE_URL:-http://localhost:8080}
server:
port: ${GATEWAY_PORT:-8080}
host: 0.0.0.0
# Operator routes (receipts, events) 404 without this. Uncomment and set it
# before exposing the gateway anywhere.
# adminToken: ${ADMIN_TOKEN}
storage:
receipts:
driver: sqlite
path: ${RECEIPT_STORE_PATH:-./data/receipts.sqlite}
protocols:
http:
enabled: true
mcp:
enabled: true
mountPath: /mcp
resources:
premium_report:
name: Premium Report
description: One paid endpoint, settled in USDC on Base Sepolia.
input:
type: object
properties: {}
additionalProperties: false
backend:
type: http
method: GET
url: ${MERCHANT_API_BASE_URL:-http://localhost:3000}/api/report
timeoutMs: 10000
pricing:
type: fixed
amount: "0.01"
currency: USDC
expose: [http, mcp]
payments: [x402]
payments:
x402:
enabled: true
# Base Sepolia. The local dev chain is eip155:31337 instead.
network: eip155:84532
rpcUrl: ${X402_RPC_URL:-https://base-sepolia-rpc.publicnode.com}
# Circle's USDC on Base Sepolia. EIP-712 domain ("USDC", "2"), 6 decimals.
asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
assetName: USDC
assetVersion: "2"
assetDecimals: 6
# Merchant-controlled. Never an Anvil development address.
payTo: ${MERCHANT_WALLET}
maxTimeoutSeconds: 300
facilitator:
mode: remote
url: ${X402_FACILITATOR_URL:-https://x402.org/facilitator}
auth:
type: noneWhat you need
| A merchant address | MERCHANT_WALLET — any address you control. Never a key. |
| A buyer with test USDC | faucet.circle.com — the buyer needs no ETH. |
| A Base Sepolia RPC | health checks and reconcile; the public RPC default works. |
MERCHANT_WALLET has no default, because the only available default would be an Anvil address — which is refused on any non-local deployment.Run it
The backend and the gateway each stay in the foreground, so give each one its own terminal.
# terminal 1: your backend, or the repository's demo merchant API
npm run dev:merchant
# terminal 2: the gateway, on Base Sepolia
MERCHANT_WALLET=0xYourMerchantAddress \
AGENT_COMMERCE_CONFIG=examples/base-sepolia/config.yaml \
npm run dev:gateway
# terminal 3: check it
MERCHANT_WALLET=0xYourMerchantAddress \
npm run agent-commerce -- doctor --config examples/base-sepolia/config.yamlTo run this config with the published package, copy it next to your API, replace its demo premium_report resource with your own endpoints and install the pinned x402 and MCP peers:
npm install @devlab.group/[email protected] @modelcontextprotocol/[email protected] @x402/[email protected] @x402/[email protected] [email protected]
MERCHANT_WALLET=0xYourMerchantAddress npx @devlab.group/agent-commerce start --config config.yamldoctor reports TESTNET on Base Sepolia (eip155:84532).
Prove it settles
X402_TESTNET_BUYER_PRIVATE_KEY=0x... \
X402_TESTNET_MERCHANT_ADDRESS=0xYourMerchantAddress \
npm run test:testnetThe suite requests a challenge, signs it and settles through the facilitator, then verifies the USDC Transfer in the on-chain receipt. The x402 amount comes from X402_SMOKE_AMOUNT, then X402_TESTNET_AMOUNT, defaulting to 0.01 USDC. Missing required variables cause an explained skip. Those credentials also enable the separate MPP Base Sepolia suite, whose amount is set by X402_TESTNET_AMOUNT (default 0.01). The smoke tests cover the other targets, such as Permit2 on Base Sepolia.
It has been run: 0xf3288399… settled 0.01 USDC on 2026-08-22.
Source: examples/base-sepolia