Skip to content

seanonchain/402qr

Repository files navigation

QR Code Creator x402

Drop-in Next.js 15 experience for creating paywalled QR codes that settle in USDC via @coinbase/x402. Replace the Nano Banana Cam imaging flow with:

  • Two QR types
    • Link – one-time ticket → HTTP 303 redirect to your target URL after payment.
    • Product – collects payment → shows a green success screen with product name, masked payer, and sequential receipt number.
  • Two creation paths
    • Human UI web forms at /create/link and /create/product.
  • Paid MCP tools served from /api/mcp using x402-mcp; agents invoke tools like create_link_qr / create_product_qr and receive QR PNG payloads after payment.
  • x402 pay endpoints
    • /api/pay/link/[slug] → mints ticket → 303/go/[nonce].
    • /api/pay/product/[id] → stores receipt → mints ticket → 303/receipt/[nonce].

Persistence is handled with Upstash Redis (REST API). Tickets are single-use keys with TTL, verified by JWTs signed server-side.


Project structure

app/
  (public)/
    create/            # Browser forms for human operators
      link/page.tsx
      product/page.tsx
    p/[slug]/page.tsx  # Link paywall UI
    buy/[id]/page.tsx  # Product paywall UI
  api/
    links/route.ts             # POST create link (returns QR PNG base64)
    products/route.ts          # POST create product (returns QR PNG base64)
    pay/
      link/[slug]/route.ts     # 402-protected link payment flow
      product/[id]/route.ts    # 402-protected product payment flow
    mcp/route.ts               # MCP server exposing paid QR creation tools
  go/[nonce]/route.ts          # Consumes ticket, 302 to target URL
  receipt/[nonce]/route.ts     # Consumes ticket, renders green receipt
lib/
  origin.ts     # resolves canonical origin for QR URLs
  qr-service.ts # shared helpers for creating link/product records + QR PNGs
  ids.ts       # nanoid helpers for slug/id generation
  money.ts     # USD ⇄ micro-USDC helpers + address masking
  qr.ts        # QRCode buffer → base64 PNG
  redis.ts     # Upstash Redis REST client
  tickets.ts   # mint/spend/verify one-time tickets
  x402.ts      # enforceX402 helper (verify + settle + requirement builder)
  x402_impl.ts # wraps @coinbase/x402 facilitator utilities

Data model (Upstash keys)

Key Value
link:<slug> { slug, targetUrl, priceMicroUSDC, network, payee }
product:<id> { id, name, priceMicroUSDC, network, payee }
ticket:<nonce> { kind: 'link' | 'receipt', refId, exp } (TTL via set + getdel)
receipt:<global> { id, productId, productName, payerAddress?, perProductSeq, txHash? }
receipt:global_seq global receipt counter (INCR)
receipt:seq:<productId> per-product counter (INCR)

Prices are stored as micro-USDC integers (e.g. $1.231230000). Tickets expire after 5–10 minutes by default and are single-use.


Environment variables

Copy .env.local.example to .env.local and provide:

CDP_API_KEY_ID=...
CDP_API_KEY_SECRET=...
NEXT_PUBLIC_CDP_PROJECT_ID=...
RECIPIENT_WALLET_ADDRESS=0xYourWallet

NEXT_PUBLIC_NETWORK=base                 # or base-sepolia
NEXT_PUBLIC_USDC_CONTRACT=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=...

KV_REST_API_URL=https://your-kv-cluster.upstash.io
KV_REST_API_TOKEN=...

SIGNED_REDIRECT_SECRET=super-long-random-string

The SIGNED_REDIRECT_SECRET secures the ticket JWT so only the server can mint/verify redirect tokens.


Getting started

  1. Install dependencies
    npm install
  2. Copy .env.local.example.env.local and fill in the variables above.
  3. Run the dev server
    npm run dev
  4. Visit:
    • http://localhost:3000/ – agent chat demo with paid tool examples.
    • http://localhost:3000/playground – job playground UI (connects to internal APIs).
    • http://localhost:3000/create/link – human link QR creator.
    • http://localhost:3000/create/product – human product QR creator.
    • http://localhost:3000/p/<slug> – sample paywall (after QR scan).
    • http://localhost:3000/buy/<id> – product paywall.

You’ll need a wallet funded with USDC on Base (or Base Sepolia for testing) plus an x402 facilitator API key.


Payment flow

  1. Client hits /api/pay/link/[slug] or /api/pay/product/[id] without payment → receives 402 with accepts.
  2. Client retries using x402-fetch, which signs and submits the payment authorization.
  3. lib/x402.ts verifies with @coinbase/x402 and settles the payment.
  4. On success:
    • Links → mintTicket("link") → redirect to /go/<nonce>?t=<jwt> → 302 to target URL after consuming the ticket.
    • Products → mintTicket("receipt") + receipt storage → redirect to /receipt/<nonce>?t=<jwt> which renders a full-page green success card.

Tickets use redis.getdel so they cannot be replayed. Both /go/* and /receipt/* set Cache-Control: no-store.


MCP (Machine Control Protocol) endpoints

Paid agent integrations live under a single MCP endpoint /api/mcp, powered by x402-mcp. Tools enforce an additional x402 fee (default $0.10) before creating the QR, and each response mirrors the human APIs (slug/id, pay_url, qr_png_base64).

Tool name Description
create_link_qr Pay-gated creation of a link QR
create_product_qr Pay-gated creation of a product QR

Agents should call these with a JSON body matching the human forms (fields: target_url/name, price_usdc, payee_address, optional network).


Configuration notes

  • wrapFetchWithPayment in the paywall pages caps spend to 10 USDC by default—tweak as needed.
  • enforceX402 returns payer + tx hash so you can enhance receipts or ledger entries.
  • Receipts expire after 1 hour. Increase TTL if you need longer-lived audit trails.
  • Update MCP_PRICE_USDC in app/api/mcp/route.ts for your desired agent fee.

Credits

  • Original Nano Banana Cam template by @EstebanSuarez.
  • x402 protocol and facilitator helpers by the Coinbase Developer Platform team.

This repo now focuses purely on QR monetization. No AI image generation, camera capture, or fal.ai dependencies remain.

About

x402 QR code creation for humans and agents

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors