TypeScript SDK
Add x402 payments to JavaScript/TypeScript applications. Supports Express, Hono, and Next.js.
npm @primersystems/x402
Installation
bash
npm install @primersystems/x402
Payer (Client)
Wrap fetch or axios to automatically handle 402 responses:
javascript
const { createSigner, x402Fetch } = require('@primersystems/x402');
// Create a signer with CAIP-2 network format
const signer = await createSigner('eip155:8453', process.env.PRIVATE_KEY);
// Wrap fetch to handle 402 automatically
const fetch402 = x402Fetch(fetch, signer, { maxAmount: '1.00' });
// Use like normal fetch — payments happen automatically
const response = await fetch402('https://api.example.com/paid-endpoint');
With Axios
javascript
const { createSigner, x402Axios } = require('@primersystems/x402');
const signer = await createSigner('eip155:8453', process.env.PRIVATE_KEY);
const axios402 = x402Axios(axios.create(), signer, { maxAmount: '1.00' });
const response = await axios402.get('https://api.example.com/paid-endpoint');
With viem
javascript
import { createWalletClient, http } from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';
import { createSigner, x402Fetch } from '@primersystems/x402';
// Create a viem wallet client
const walletClient = createWalletClient({
account: privateKeyToAccount(process.env.PRIVATE_KEY),
chain: base,
transport: http()
});
// Pass the wallet client directly to createSigner
const signer = await createSigner(walletClient);
const fetch402 = x402Fetch(fetch, signer, { maxAmount: '1.00' });
Payer Options
| Option | Required | Description |
|---|---|---|
maxAmount |
Yes | Maximum payment per request (e.g., '1.00') |
facilitator |
No | Custom facilitator URL |
verify |
No | Verify payment before sending (default: true) |
Payee (Server)
Add payment requirements to your API routes using middleware.
Express
javascript
const { x402Express } = require('@primersystems/x402');
app.use(x402Express('0xYourWalletAddress', {
'/api/premium': {
amount: '0.01', // $0.01 USDC
asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
network: 'eip155:8453' // Base mainnet
},
'/api/data/*': {
amount: '0.001',
asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
network: 'eip155:8453'
}
}));
Hono
javascript
const { x402Hono } = require('@primersystems/x402');
app.use('*', x402Hono('0xYourWalletAddress', {
'/api/premium': {
amount: '0.01',
asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
network: 'eip155:8453'
}
}));
Next.js (App Router)
javascript
import { x402Next } from '@primersystems/x402';
async function handler(req) {
return Response.json({ data: 'premium content' });
}
export const GET = x402Next(handler, {
payTo: '0xYourWalletAddress',
amount: '0.01',
asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
network: 'eip155:8453'
});
Single Route Protection
For protecting individual routes without full middleware:
javascript
const { x402Protect } = require('@primersystems/x402');
app.get('/api/premium',
x402Protect('0xYourWallet', '0.01', '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', 'eip155:8453'),
(req, res) => {
res.json({ data: 'premium content' });
}
);
Token Approval (ERC-20)
For non-EIP-3009 tokens, approve the Prism contract once:
javascript
const { createSigner, approveToken } = require('@primersystems/x402');
const signer = await createSigner('eip155:8453', process.env.PRIVATE_KEY);
// One-time approval (requires gas)
await approveToken(signer, '0xTokenAddress');
// Now payments with this token are gasless
Custom Facilitator
For non-Base networks, specify your own facilitator:
javascript
// Payee
app.use(x402Express('0xAddress', routes, {
facilitator: 'https://your-facilitator.com'
}));
// Payer
const fetch402 = x402Fetch(fetch, signer, {
maxAmount: '1.00',
facilitator: 'https://your-facilitator.com'
});
Testing
The SDK includes utilities for testing without real payments:
javascript
const { createMockFacilitator, createTestPayment } = require('@primersystems/x402/testing');
describe('paid endpoint', () => {
let mock;
beforeAll(async () => {
mock = await createMockFacilitator({ mode: 'approve' });
});
afterAll(() => mock.close());
test('accepts payment', async () => {
const payment = createTestPayment({ amount: '10000' });
const res = await fetch('/api/premium', {
headers: { 'PAYMENT-SIGNATURE': payment }
});
expect(res.status).toBe(200);
});
});
Debug Logging
bash
DEBUG=x402:* node app.js
DEBUG=x402:payer,x402:payee node app.js