Production-ready Next.js 15 application with stateless HTTP 402 payments and PEAC receipts.
- Stateless 402 sessions: No database required
- Serverless-friendly: Works on Vercel Edge/Node runtimes
- Landing page: Beautiful gradient hero with features
- Shop demo: Cart checkout with x402 payments
- Offline verifier: Verify any PEAC receipt
- Discovery endpoints:
/.well-known/peac.txt, public keys, AIPREF
npm install
cp .env.example .env.local
# Edit .env.local with your signing key
npm run devVisit http://localhost:3000
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel --prodConfigure in Vercel Dashboard (Settings → Environment Variables):
PEAC_SIGNING_JWK={"crv":"Ed25519","d":"...","x":"...","kty":"OKP","alg":"EdDSA","use":"sig"}
PEAC_KID=peac-prod-key-1
DEMO_MODE=true
DEMO_TOKEN=demo-pay-ok-123
X402_CHAIN=base
X402_CURRENCY=USDC
PUBLIC_ORIGIN=https://x402.peacprotocol.org
NEXT_PUBLIC_ORIGIN=https://x402.peacprotocol.orgFor production x402 payments:
DEMO_MODE=false
FACILITATOR_VERIFY_URL=https://your-facilitator.com/verify
FACILITATOR_API_KEY=sk_x402_...node -p "
const { generateKeyPair } = require('jose');
(async () => {
const { publicKey, privateKey } = await generateKeyPair('EdDSA', { crv: 'Ed25519' });
const jose = await import('jose');
const priv = await jose.exportJWK(privateKey);
const pub = await jose.exportJWK(publicKey);
priv.kid = 'peac-prod-key-1';
priv.alg = 'EdDSA';
priv.use = 'sig';
console.log('PEAC_SIGNING_JWK=' + JSON.stringify(priv));
})();
"Session state is encoded in signed JWT tokens:
- Client requests checkout → Server returns
402withsession_token(JWS) - Token contains:
{sid, subject, amount, currency, chain, issued_at} - Client pays, gets
proof_id - Client retries with
X-402-Session: <token>+X-402-Proof: <proof> - Server verifies token signature + validates proof
- Server returns
200 OKwithPEAC-Receiptheader
Benefits:
- No database or Redis needed
- Horizontally scalable
- Works on serverless platforms
- No session cleanup required
GET /api/shop/catalog- Product listPOST /api/shop/cart- Create cartPOST /api/shop/cart/:id/add- Add itemsPOST /api/shop/checkout- Stateless 402 + receipt issuancePOST /api/verify- Verify receiptsGET /.well-known/peac.txt- PEAC discoveryGET /public-keys/:kid- Public verification key
/- Landing page/shop- Cart checkout demo/verify/offline- Receipt verifier
Set x402.peacprotocol.org as primary domain in Vercel.
Configure in vercel.json:
{
"redirects": [
{
"source": "https://demo.peacprotocol.org/:path*",
"destination": "https://x402.peacprotocol.org/:path*",
"permanent": true
}
]
}# Test discovery
curl https://x402.peacprotocol.org/.well-known/peac.txt
# Test 402 challenge
curl https://x402.peacprotocol.org/api/shop/checkout \
-H "Content-Type: application/json" \
-d '{"cart_id":"cart_xyz"}'
# Test with demo token
curl -i https://x402.peacprotocol.org/api/shop/checkout \
-H "Content-Type: application/json" \
-H "X-402-Session: <session_token>" \
-H "X-402-Proof: demo-pay-ok-123" \
-d '{"cart_id":"cart_xyz"}'Edit lib/catalog.ts:
export const CATALOG: Product[] = [
{ sku: 'custom', title: 'Custom Product', price_usd: 0.10 },
];Edit public/aipref.json to reflect your policies.
- Metadata:
app/layout.tsx - Landing page:
app/page.tsx - Colors: Tailwind config
- API routes: Node.js runtime for crypto operations
- Static pages: Edge runtime
- CDN: Vercel Edge Network
- Caching: Public key and discovery endpoints cached
- Private keys in environment variables only
- EdDSA signatures (Ed25519)
- Session tokens time-bound
- No secrets in client code
- CORS headers on receipts
Ensure PEAC_SIGNING_JWK is set correctly in Vercel environment variables.
Check FACILITATOR_VERIFY_URL and FACILITATOR_API_KEY are correct for production mode.
Ensure Node.js 20+ is selected in Vercel project settings.