Public
Playing with internet-native payment protocols
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

x402 Playground

πŸ“Ί Explainer video + demo walkthrough

A demo app showing both sides of the x402 protocol (HTTP 402 payments) β€” a buyer that pays for APIs with USDC, and a seller that charges for an API endpoint. All powered by automatic micropayments on Base.

Two Apps, One Wallet

This project contains two HTTP endpoints that share the same wallet (X402_PRIVATE_KEY):

AppFileRoleDescription
Buyerbuyer.tsxPays for APIsWeb UI that calls paid x402 endpoints using @x402/fetch
Sellerseller.tsxCharges for an APIHono app with @x402/hono middleware protecting GET /api/random

Since both use the same wallet, calling the seller from the buyer sends $0.001 USDC from yourself to yourself β€” a perfect zero-cost demo loop. Gas is sponsored by the xpay facilitator (Base L2 gas costs fractions of a penny, so facilitators subsidize it to drive adoption of x402).

How it Works

Buyer β†’ Seller Flow (Random Number)

Rendering mermaid diagram...

Buyer β†’ Browserbase Flow (Screenshot)

Rendering mermaid diagram...

Project Structure

buyer.tsx                β†’ HTTP entry point for buyer app (Hono router)
seller.tsx               β†’ HTTP entry point for seller app (Hono + x402 middleware)
routes/
  home.tsx               β†’ Buyer landing page with screenshot & random number forms
  screenshot.tsx         β†’ Screenshot form + POST handler (pays Browserbase)
  random.tsx             β†’ Random number handler (pays our own seller.tsx)
  transactions.tsx       β†’ Transaction history table
lib/
  x402.ts                β†’ x402 client setup (wallet signer + wrapFetchWithPayment)
  browserbase.ts         β†’ Browserbase session creation via x402
  screenshot.ts          β†’ Playwright CDP screenshot capture
  db.ts                  β†’ SQLite schema & queries for transaction log
  layout.tsx             β†’ Shared HTML layout with Twind CSS

Environment Variables

KeyDescription
X402_PRIVATE_KEYPrivate key for a Base wallet holding USDC (used by both buyer and seller)

Pages

Buyer (buyer.tsx)

RouteDescription
/Home β€” screenshot form, random number button, wallet info
/screenshotCapture a website screenshot ($0.01 USDC via Browserbase)
/randomGet a random number ($0.001 USDC via our seller)
/transactionsTable of past payments with totals and tx hashes

Seller (seller.tsx)

RouteDescription
/Homepage explaining the API and pricing
/api/randomPaid endpoint β€” returns { random: Math.random() } for $0.001 USDC

Key Details

  • Network: Base mainnet (eip155:8453)
  • Currency: USDC
  • Facilitator: xpay.sh (zero fees, gas sponsored)
  • Seller price: $0.001 per random number
  • Screenshot price: $0.01 per session (paid to Browserbase)

Wallet Setup

To run this yourself, you need a Base wallet with USDC and its private key. Here's how to set one up:

  1. Install the Coinbase Wallet Chrome extension (the iOS/Android app works too, but exporting the private key is easier from the extension)
  2. Create a new wallet
  3. Click Buy β†’ Add with Coinbase Onramp
  4. Important: If you have a personal Coinbase account, fully log out of it first β€” otherwise the onramp may try to use your existing account and get confused
  5. Buy USDC on Base with a debit card (Apple Pay also works)
  6. Export the private key: Settings β†’ Developer Settings β†’ Show private key
  7. Add it as X402_PRIVATE_KEY in your val's environment variables
  8. Note: You may need to prefix the key with 0x β€” the key exported from Coinbase Wallet doesn't include it, but viem expects it