Skip to main content
The Vercel template is a standalone Next.js app that clones into your GitHub and deploys a working pay-per-call API. The demo is a fortune teller that exercises every pricing mode.
1

Click deploy

Deploy with VercelVercel clones only the template directory into a fresh repo in your GitHub account.
2

Set three environment variables

The deploy flow prompts for them inline:
  • EVM_PAYEE_ADDRESS: the 0x… wallet that receives payments.
  • CDP_API_KEY_ID and CDP_API_KEY_SECRET: Coinbase Developer Platform credentials for the default x402 facilitator. The CDP free tier is enough.
BASE_URL is auto-derived from Vercel’s system env vars, so there is no manual step.
3

Call it

The landing page at your deployment’s root lists every endpoint with a copy-pasteable command:
npx agentcash fetch https://<your-domain>/api/fortune -m POST
Add Upstash Redis / Vercel KV from the Vercel Storage tab before production traffic. Without it, SIWX entitlement and replay state is per-Lambda-instance and pay-once-then-replay routes break at scale. See Configuration.
To make it your own, replace the routes in app/api/fortune/* with your endpoints, add each new route file to lib/routes.ts, and update the title and guidance in lib/router.ts. Push to GitHub and Vercel redeploys.

Minimal server from scratch

The router runs on any fetch runtime, including Next.js, Hono, Bun, and Node. Below is a complete server in one file, using Hono on Node:
1

Create the project

mkdir my-api && cd my-api
npm init -y
npm i @agentcash/router hono @hono/node-server zod
npm i -D tsx
2

Write the server

server.ts
import { serve } from '@hono/node-server';
import { Hono } from 'hono';
import { createRouterFromEnv } from '@agentcash/router';
import { z } from 'zod';

const router = createRouterFromEnv({
  title: 'Quote API',
  description: 'Pay-per-call quotes.',
  guidance: 'GET /api/health is free. POST /api/quote with { topic } returns a quote for $0.001.',
});

router
  .route('quote')
  .paid('0.001')
  .body(z.object({ topic: z.string() }))
  .description('Random quote for a topic')
  .handler(async ({ body }) => ({ quote: pickQuote(body.topic) }));

router
  .route({ path: 'health', method: 'GET' })
  .unprotected()
  .handler(async () => ({ ok: true }));

const app = new Hono();
app.route('/', router.hono());
serve({ fetch: app.fetch, port: 3000 });
3

Set the environment and run

export BASE_URL=http://localhost:3000   # 402 realm + OpenAPI server URL
export EVM_PAYEE_ADDRESS=0x...          # receives payments
export CDP_API_KEY_ID=...               # Coinbase Developer Platform key
export CDP_API_KEY_SECRET=...           #   (free tier: portal.cdp.coinbase.com)

npx tsx server.ts                       # http://localhost:3000
Routes serve at /api/*, and discovery (/openapi.json, /llms.txt) works immediately.
4

Deploy anywhere

The server is a plain Node process: deploy it to Fly, Railway, a VPS, or any container host. Set BASE_URL to your public origin (it’s the 402 realm and OpenAPI server URL, so it must match the domain agents call), and add an Upstash KV for production. See Configuration.
The runnable version of this server lives at examples/hono. Bun, Deno, and Cloudflare Workers work the same way via router.fetch. See Hosting.

Add to an existing app (Next.js)

1

Install

pnpm add @agentcash/router zod
zod (v4) is a peer dependency.
2

Create the router

createRouterFromEnv reads config from process.env and validates every value up front. Set EVM_PAYEE_ADDRESS, CDP_API_KEY_ID, and CDP_API_KEY_SECRET (plus BASE_URL outside Vercel).
lib/router.ts
import { createRouterFromEnv } from '@agentcash/router';

export const router = createRouterFromEnv({
  title: 'My API',
  description: 'Pay-per-call search.',
  guidance: 'POST /search with { q: string }. Returns top 10 results.',
});
3

Register routes

One side-effect module registers every route:
lib/routes.ts
import { z } from 'zod';
import { router } from './router';

router
  .route('search')
  .paid('0.01')
  .body(z.object({ q: z.string() }))
  .handler(async ({ body }) => search(body.q));
4

Serve it

// app/api/[[...route]]/route.ts
import '@/lib/routes'; // side-effect import: registers all routes
import { router } from '@/lib/router';
import { nextHandlers } from '@agentcash/router/next';

export const { GET, POST, PUT, PATCH, DELETE } = nextHandlers(router);
import { serve } from '@hono/node-server';
import './routes';
import { router } from './router';

serve({ fetch: router.fetch, port: 3000 });
On Next.js, add the root discovery aliases with two one-line route files. See Hosting.

Test the 402 flow

An unpaid request gets a 402 whose challenge lives in headers:
curl -i -X POST https://api.example.com/api/search \
  -H 'content-type: application/json' -d '{"q":"hello"}'
Pay it with any x402 or MPP client:
# AgentCash CLI: auto-negotiates x402 or MPP
npx agentcash fetch https://api.example.com/api/search -m POST -b '{"q":"hello"}'

# mppx CLI: MPP reference client
npx mppx https://api.example.com/api/search -J '{"q":"hello"}'