Frontend application demonstrating the x402 payment protocol with real on-chain USDC payments via EIP-3009 (TransferWithAuthorization).
This frontend connects to an x402-server backend that handles:
- HTTP 402 responses with payment requirements
- Payment verification via EIP-712 signatures
- Settlement through the x402 facilitator
- Media file serving with token-based access
- User clicks on locked content
- Frontend sends POST to
/media/:id/access - Backend returns HTTP 402 with
paymentRequiredobject - User signs EIP-712 authorization (EIP-3009)
- Frontend sends signed payload to backend
- Backend verifies and settles via facilitator
- Backend returns
mediaUrlwith access token - Content is unlocked
- x402 Version: 2
- Signature: EIP-712 typed data (TransferWithAuthorization)
- Asset: USDC (6 decimals)
- Network: Base Sepolia (testnet) / Base (mainnet)
- Price: $0.01 USDC per media item
- Real-time server connection status (online/offline)
- Displays network name (Base Sepolia / Base Mainnet)
- Auto-refreshes media when server comes back online
- Connect/disconnect wallet functionality
- Persists connection state across page refreshes
- Manual disconnect prevents auto-reconnect until user clicks Connect again
- Supports account switching in wallet extension
- Preview images/videos served from
/media/preview/:id(server-side blur recommended) - Full content served with token after payment:
/media/:file?token=... - Placeholder shown when server is offline
- Step-by-step progress indicator (Request → Sign → Settle → Done)
- Real-time status updates during transaction
- Explorer link after successful payment
- Manual close - user controls when to dismiss
- Unlocked content stored per wallet address in sessionStorage
- Different wallets have separate unlock states
- Switching wallets shows appropriate locked/unlocked state
- Node.js 18+
- MetaMask or Coinbase Wallet
- USDC on Base Sepolia (for testing)
- ETH on Base Sepolia (for gas)
npm install
cp .env.example .envEdit .env:
# Backend API URL
VITE_API_URL=http://localhost:3000Start the x402-server backend first (in another terminal):
# In x402-server directory
npm run devThen start this frontend:
npm run devsrc/
config/
x402-config.ts # API config, types, formatters
hooks/
use-x402-payment.ts # Payment logic, EIP-712 signing, wallet management
components/
video-player.tsx # Video with paywall and server status handling
image-viewer.tsx # Image with paywall and server status handling
payment-modal.tsx # Payment UI with progress steps
payment-modal.css # Payment modal styles
wallet-connect.tsx # Wallet connection UI
App.tsx # Main application
App.css # Application styles
GET /media/preview/video
GET /media/preview/image
POST /media/video/access
POST /media/image/access
{
"success": false,
"error": "Payment Required",
"media": {
"id": "video",
"title": "Premium Video",
"type": "video",
"priceUsd": 0.01
},
"paymentRequired": {
"x402Version": 2,
"accepts": [{
"scheme": "exact",
"network": "eip155:84532",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"payTo": "0x...",
"amount": "10000"
}]
}
}POST /media/video/access
{
"message": {
"metadata": {
"x402.payment.payload": {
"x402Version": 2,
"resource": { ... },
"accepted": { ... },
"payload": {
"signature": "0x...",
"authorization": {
"from": "0x...",
"to": "0x...",
"value": "10000",
"validAfter": "0",
"validBefore": "...",
"nonce": "0x..."
}
}
},
"x402.payment.status": "payment-submitted"
}
}
}{
"success": true,
"mediaUrl": "http://localhost:3000/media/video.mp4?token=...",
"mediaType": "video",
"grant": {
"id": "grant-...",
"mediaId": "video",
"payer": "0x...",
"expiresAt": 1234567890
},
"settlement": {
"success": true,
"transaction": "0x...",
"network": "eip155:84532"
}
}GET /media/video.mp4?token=...
GET /media/image.jpg?token=...
- Base Sepolia Faucet: https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet
- USDC Faucet: https://faucet.circle.com/
- Block Explorer: https://sepolia.basescan.org
Wszelkie prawa zastrzeżone. 2025 Defdone.