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
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. Chain id 84532 is shared with the local dev chain, which
# is why `local` vs `testnet` is decided by the facilitator below.
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 only; the public default works. |
Unlike the local examples this one does not validate with no environment set:
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
# 1. your backend, or the repository's demo merchant API
npm run dev:merchant
# 2. the gateway, on Base Sepolia
MERCHANT_WALLET=0xYourMerchantAddress \
AGENT_COMMERCE_CONFIG=examples/base-sepolia/config.yaml \
npx tsx src/gateway/main.ts
# 3. check it
MERCHANT_WALLET=0xYourMerchantAddress \
npm run agent-commerce -- doctor --config examples/base-sepolia/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 asks unpaid, signs the challenge, settles through the facilitator and reads the balances and transaction receipt back from the chain. It spends X402_TESTNET_AMOUNT (default 0.01) per run and skips itself without those variables.
Source: examples/base-sepolia