x402 Suite · USDC on Base or Solana

The timetable is free. The seat is the product.

A self-hosted class booking server with x402 micropayments. Reading the schedule costs nothing; $0.05 buys a seat and the payment returns the seat number, the full class details, a calendar invite and a signed QR pass the door can scan — all in the same HTTP response. Pay in USDC on Base or Solana — your client picks the rail.

git clone https://github.com/nirholas/x402-classes cd x402-classes && npm install npm run dev # runs out of the box, both rails live

Pricing

RoutePriceThe artifact you get back
GET /schedulefreeThe class calendar with live seat counts — sessions, instructors, rooms, seatsLeft, enrollmentOpen
POST /enroll/:classId$0.05{seatNumber, classDetails, ics (base64 invite), pass: {token, verifyUrl, qrSvgDataUri, expiresAt}, signature}
GET /verify/:tokenfreePass validation for the door — valid, payload, check-in status, session
POST /check-in/:tokenfreeMarks a pass used; re-scans report alreadyCheckedIn
GET /roster/:classIdfreeSeats sold: seat number, holder name, check-in status
GET /.well-known/x402freeMachine-readable payment manifest for agents and indexers

Every paid route returns the thing you bought in the 200 body. No pay-now-deliver-later.

How a paid call works

1 · Request

POST /enroll/:classId with no payment. Server replies 402 with an accepts[] holding both rails — amount, token address and recipient on Base and on Solana.

2 · Pay (your pick)

Base: sign an EIP-3009 USDC authorization. Solana: sign an SPL transferChecked. Retry with the X-PAYMENT header; that rail's facilitator verifies and settles on the chain you chose.

3 · Artifact

200 with the seat, the invite and the QR pass in the body and a settlement receipt in X-PAYMENT-RESPONSE, naming the rail. Settlement only runs on success.

Two rails, one price

USDC on Base (EVM)

network
base-sepolia (default) · base
asset
0x036CbD53842c5426634e7929541eC2318f3dCF7e
payTo
0x40252CFDF8B20Ed757D61ff157719F33Ec332402
signature
EIP-3009 transferWithAuthorization
facilitator
https://x402.org/facilitator

USDC on Solana (SVM)

network
solana (default) · solana-devnet
asset
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
payTo
WwwuGbqHrwF5RG89KhUbmRWEvjnRH9k5kVM5p7T3WwW
signature
SPL transferChecked (serialized tx)
facilitator
https://facilitator.payai.network

Quickstart — agent side

import { wrapFetchWithPayment } from "x402-fetch";
import { privateKeyToAccount } from "viem/accounts";

const payFetch = wrapFetchWithPayment(fetch, privateKeyToAccount(PRIVATE_KEY));

// the schedule is free — no wallet needed to browse
const { sessions } = await fetch("http://localhost:4023/schedule?days=7").then(r => r.json());
const session = sessions.find(s => s.seatsLeft > 0 && s.enrollmentOpen);

const ticket = await payFetch(`http://localhost:4023/enroll/${session.classId}`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ name: "Agent Ada" }),
}).then(r => r.json());

console.log(ticket.seatNumber, ticket.pass.verifyUrl, ticket.pass.qrSvgDataUri);

Explore

Human checkout demo

Studio-style flow with the drop-in payment modal — browse the free timetable, tap a class, pay with Phantom (Solana) or MetaMask (Base), get the QR pass on screen.

public/index.html →

For AI agents

skill.md + .well-known/x402 discovery, MCP tool wrapper for Claude, listing on x402scan / Bazaar.

agents.md →

API reference

Every endpoint with params, prices, schemas, and error cases. OpenAPI 3.1 included.

api.md →

Raw wire flow

The exact 402 → pay → 200 exchange in curl, header by header.

examples/curl.md →