Overview
This demo shows a complete Agent-to-Agent (A2A) payment flow using the x402 payments extension and the Crossmint Wallets SDK in a single React web app plus a tiny merchant server.What It Does
Server (Merchant)
- Advertises the x402 extension via its AgentCard
- Replies to the first client message with payment requirements (
x402.payment.required) - Verifies payment using the
direct-transferscheme by reading ERC-20Transferlogs on-chain - Publishes a receipt with the transaction hash when everything matches
Client (React App)
- Presents a simple UI for the A2A flow
- Uses Crossmint Wallets to create/load the payer wallet
- Sends an ERC-20
transferfrom that wallet - Submits the tx hash back over x402
- Live-updates balances and status once the server confirms
Sequence Flow
Quick Start
Prerequisites
- Node.js 18+ and npm
- A
.envfile with your Crossmint credentials
1. Setup Environment
| Variable | Description | Default |
|---|---|---|
RPC_URL | RPC URL for the merchant server to connect to | - |
MERCHANT_ADDRESS | The merchant payee address | Required |
ASSET_ADDRESS | USDC contract address | 0x036CbD53842c5426634e7929541eC2318f3dCF7e (Base Sepolia) |
X402_NETWORK | Network identifier | base-sepolia |
2. Install Dependencies
3. Start Both Services
4. Open the Demo
- React App: http://localhost:3000
- Server API: http://localhost:10000
- AgentCard: http://localhost:10000/.well-known/agent-card.json
Key Points
Crossmint is the payer in this demo. You do not need a user private key; the Crossmint wallet service signs and sends the transfer, and the server verifies it on-chain. The merchant config only requires
MERCHANT_ADDRESS.Getting Testnet Tokens
Base Sepolia USDC: Use the Circle Faucet and send to your Crossmint wallet address.Scripts
Behind the Scenes
Discovery and Activation
The client opts in to the payments extension and loads the merchant’s AgentCard using theX-A2A-Extensions header. See A2AClient.fromCardUrl and fetchWithExtension in app/page.tsx.
Request and Requirements
The client sends an initial message; the merchant replies with a Task whose messagemetadata includes:
x402.payment.status: "payment-required"x402.payment.required
handlePayment() in app/page.tsx.
Wallet Setup (Payer)
A Crossmint wallet is created/loaded foremail:{userEmail} on the requested chain. See:
createCrossmintCrossmintWallets.fromwallets.createWalletinapp/page.tsx
Direct Transfer
The client executes ERC-20transfer(payTo, amount) from the Crossmint wallet. See evmWallet.sendTransaction usage in handlePayment().
Payment Submission
The tx hash and details are sent back with:x402.payment.status: "payment-submitted"x402.payment.payload
Server Verification
The server:- Checks the receipt
- Verifies the
Transferlog for exact payer, payTo, and amount - Publishes
payment-completedwith a receipt
server.js.
Receipts and Balances
The client:- Reads
x402.payment.receipts - Refreshes balances via RPC + ERC-20 calls
checkBalances() in app/page.tsx.
Payment Schemes
This demo uses thedirect-transfer payment scheme:
- Client performs a direct ERC-20 transfer
- Server verifies the transaction on-chain
- No signature verification needed (transaction itself is proof)
- Simpler than EIP-3009 but requires gas fees from payer