TypeScript SDK
Add x402 payments to JavaScript/TypeScript applications. Supports Express, Hono, and Next.js.
npm @primersystems/x402
Installation
npm install @primersystems/x402
Quick Start (CLI)
New in v0.5.0 — manage wallets, probe URLs, and make payments from the command line:
# Create a new wallet
npx @primersystems/x402 wallet create
# Check wallet balance
npx @primersystems/x402 wallet balance 0xYourAddress
# Check if a URL requires payment (and get price)
npx @primersystems/x402 probe https://api.example.com/paid
# Preview payment without paying
npx @primersystems/x402 pay https://api.example.com/paid --dry-run
# Make a payment
X402_PRIVATE_KEY=0x... npx @primersystems/x402 pay https://api.example.com/paid --max-amount 0.10
CLI Commands
| Command | Description |
|---|---|
wallet create | Create a new wallet (address, private key, mnemonic) |
wallet balance <address> | Check USDC balance |
wallet from-mnemonic | Restore wallet from mnemonic |
probe <url> | Check if URL requires payment |
pay <url> | Make a payment (requires X402_PRIVATE_KEY) |
pay <url> --dry-run | Preview payment without paying |
networks | List supported networks |
openclaw init | Set up for OpenClaw agents |
Environment Variables
| Variable | Description |
|---|---|
X402_PRIVATE_KEY | Wallet private key (required for payments) |
X402_NETWORK | Default network (default: base) |
X402_MAX_AMOUNT | Default max payment amount in USDC |
X402_FACILITATOR | Custom facilitator URL |
Wallet Utilities
New in v0.5.0 — programmatic wallet management:
const { createWallet, walletFromMnemonic, getBalance, x402Probe } = require('@primersystems/x402');
// Create a new wallet
const wallet = createWallet();
console.log(wallet.address); // 0x...
console.log(wallet.privateKey); // 0x...
console.log(wallet.mnemonic); // "word1 word2 ..."
// Restore from mnemonic
const restored = walletFromMnemonic('word1 word2 ...');
// Check balance
const balance = await getBalance('0x...', 'base', 'USDC');
console.log(balance.balance); // "100.50"
// Probe a URL for x402 support
const probe = await x402Probe('https://api.example.com/paid');
if (probe.supports402) {
console.log('Payment required:', probe.requirements);
}
Error Handling
New in v0.5.0 — structured errors for programmatic handling:
const { X402Error, ErrorCodes } = require('@primersystems/x402');
try {
const response = await x402Fetch(url, signer, { maxAmount: '0.10' });
} catch (error) {
if (error instanceof X402Error) {
switch (error.code) {
case ErrorCodes.INSUFFICIENT_FUNDS:
console.log('Need more funds:', error.details);
break;
case ErrorCodes.AMOUNT_EXCEEDS_MAX:
console.log('Payment too expensive:', error.details);
break;
case ErrorCodes.SETTLEMENT_FAILED:
console.log('Settlement failed:', error.details);
break;
}
}
}
Error Codes
| Code | Description |
|---|---|
INSUFFICIENT_FUNDS | Wallet balance too low |
AMOUNT_EXCEEDS_MAX | Payment exceeds maxAmount |
SETTLEMENT_FAILED | Facilitator settlement failed |
INVALID_RESPONSE | Malformed 402 response |
MISSING_PRIVATE_KEY | Private key not provided |
UNSUPPORTED_NETWORK | Network not supported |
Payer (Client)
Wrap fetch or axios to automatically handle 402 responses:
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
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
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
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
const { x402Hono } = require('@primersystems/x402');
app.use('*', x402Hono('0xYourWalletAddress', {
'/api/premium': {
amount: '0.01',
asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
network: 'eip155:8453'
}
}));
Next.js (App Router)
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:
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:
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:
// 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:
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
DEBUG=x402:* node app.js
DEBUG=x402:payer,x402:payee node app.js
OpenClaw Integration
This SDK is compatible with OpenClaw AI agents. Set up your agent with one command:
npx @primersystems/x402 openclaw init
This creates a wallet, configures the network, and installs the x402 skill. Check status with:
npx @primersystems/x402 openclaw status