TypeScript SDK
Gate any HTTP route for stablecoin payments with @solana/pay-kit — one config object, web-standard Request/Response, and Express, Hono, or Fetch handlers.
@solana/pay-kit is protocol-agnostic payment gating for HTTP services on Solana. Pick a currency, give it your wallet address, and gate a route — the SDK runs the 402 Payment Required handshake (over MPP or x402), verifies the on-chain payment, and settles it. You do not need to know anything about Solana to use it.
The whole server is one createPayKit call plus your handlers. The runtime is web-standard Request/Response, so Express, Hono, and plain node:http all sit on the same dispatcher.
Install
npm install @solana/pay-kitpnpm add @solana/pay-kitbun add @solana/pay-kit@solana/pay-kit declares the protocol layer (@solana/mpp), @solana/kit, and mppx as peer dependencies — npm, pnpm, and bun install them automatically.
Quick start
Create the server
createPayKit takes a single config object: the network, your operator wallet, the protocols you accept, and an inline pricing catalogue. Gate names are inferred from pricing, so pay.express('quote') autocompletes and a typo is a compile error.
import express from 'express';
import { createPayKit, usd } from '@solana/pay-kit';const pay = await createPayKit({ accept: ['mpp', 'x402'], // settle over either protocol — the client picks network: 'mainnet', operator: { recipient: RECIPIENT, signer }, // KeyPairSigner verifies the charge pricing: { quote: { amount: usd('0.01'), description: 'Stock quote' } }, rpcUrl,})const app = express()// `pay.express(gate)` settles the 402 (MPP or x402) before the handler runs.app.get('/api/v1/quote/:symbol', pay.express('quote'), (_req, res) => { res.json({ ok: true })})Gate your routes
pay.express(gate) settles the 402 (MPP or x402, the client's choice) before your handler runs. If no valid payment was sent it halts with a 402 challenge; when one was, it verifies and settles it, sets the settlement headers on the response, and hands control to your handler.
The same instance also exposes pay.hono(gate) and pay.fetch(gate, handler) for other runtimes — see Schemes and Client.
Run it
npx tsx server.tsMake a paid call
Hit the route with the pay CLI — it walks the user through approval and pays in USDC:
pay curl http://localhost:3000/api/v1/quote/AAPL@solana/pay-kit/client ships a payment-aware fetch. On a 402 it reads the challenge, pays with the matching protocol, and retries the request with the Authorization: Payment credential — transparently.
import { createPayKitClient } from '@solana/pay-kit/client';
import { createKeyPairSignerFromBytes, getBase58Encoder } from '@solana/kit';const signer = await createKeyPairSignerFromBytes(getBase58Encoder().encode(SECRET))const client = await createPayKitClient({ signer, rpcUrl: 'http://localhost:8899' })// On a 402, pay-kit pays with the matching protocol and retries — transparently.const res = await client.fetch('https://api.example.com/api/v1/quote/AAPL')console.log(await res.json())See Client for forcing a rail and consuming streamed sessions.
No code at all — the pay CLI is a client for any 402-gated route, handling wallet, signing, and the payment retry for you:
brew install pay # or: npm install -g @solana/pay
pay --sandbox curl https://debugger.pay.sh/mpp/quote/AAPLNext steps
- Payment schemes — fixed charge, metered usage, subscription, and session.
- Pricing & gates — currencies, fees, splits, and dynamic pricing.
- Client — the paying side.
- Signers — local keys and remote signing backends.
- Errors — the error types and the boot-time safety rails.