Skip to main content
By the end of this guide you will have a running server that:
  • Exposes a plan catalog at GET /discover
  • Issues a USDC payment challenge at POST /x402/access
  • Settles the on-chain payment and returns a signed JWT (AccessGrant)
  • Protects your own routes with validateAccessToken middleware
New to Key0? Read Core Concepts first to understand terms like Plan, Challenge, AccessGrant, and EIP-3009.

Prerequisites

Before you begin, make sure you have:
  • Bun v1.3+ (or Node.js 18+)
  • A wallet address on Base Sepolia (testnet) — get testnet USDC from faucet.circle.com (select Base Sepolia)
  • Redis running locally or remotely (Postgres is also supported — see Storage)
Never use mainnet for development or testing. Base Sepolia testnet USDC has no real value and is free from the faucet.

Setup

1

Install dependencies

2

Configure and mount

Create a server.ts file. Key0 mounts as middleware on your existing server — it adds the agent card endpoint (/.well-known/agent.json), the plan discovery endpoint (/discover), the payment endpoint (/x402/access), and leaves your existing routes untouched.
3

Set environment variables

Create a .env file in your project root:
.env
ACCESS_TOKEN_SECRET must be at least 32 characters. This secret is used to sign JWTs issued to agents after payment. Use a cryptographically random string.
4

Run and test

Start your server:
Test the agent card, plan discovery, and payment endpoints with curl:
Agent card
Expected output
Browse plans (returns 200 with plan catalog)
Expected output
Request access (returns 402 challenge)
Expected output (HTTP 402)
The agent card describes your service. The discovery endpoint lists all plans — use the planId values when requesting access. The access endpoint creates a PENDING challenge containing the payment amount, destination wallet, and chain ID. A client uses the challenge to sign an EIP-3009 authorization and submit payment. See Paying for Access for the full client walkthrough.

Optional: Pay-Per-Request Routes

The quickstart above uses a subscription plan — the agent pays once and receives a signed JWT that grants access for the token’s lifetime. Key0 also supports pay-per-call routes, where each API call is paid for individually and no JWT is issued. The difference in configuration is adding a paid route to top-level routes:
On the server side, instead of protecting routes with validateAccessToken, you gate them with key0.payPerRequest() middleware. The middleware handles the entire payment cycle inline: it returns a 402 if no payment header is present, settles on-chain if it is, then calls next() so your route handler runs normally:
See the Express integration guide for a complete per-request example with all three frameworks, and PPR Embedded for a runnable demo.

What’s next

Pay-Per-Request (Embedded)

Full example: weather and joke routes with inline payment settlement.

Integrations

Detailed integration guides for Express, Hono, Fastify, and MCP.

Storage Setup

Configure Redis or Postgres for challenge and transaction storage.

Building a Seller

End-to-end guide covering plans, storage, mainnet, and production deployment.