Examples
Complete examples demonstrating various Shade402 use cases.
Express Server Example
Complete Express.js server with payment-protected endpoints:
import express from 'express';
import cors from 'cors';
import { initX402, paymentRequired, x402ErrorMiddleware } from '@shade402/express';
import { generateKeyPair } from '@shade402/core';
const app = express();
app.use(cors());
app.use(express.json());
// Generate encryption keys
const { publicKey, privateKey } = generateKeyPair();
// Initialize X402
initX402({
paymentAddress: process.env.PAYMENT_WALLET_ADDRESS!,
tokenMint: process.env.TOKEN_MINT!,
network: process.env.SOLANA_NETWORK || 'solana-devnet',
rpcUrl: process.env.SOLANA_RPC_URL,
defaultAmount: '0.01',
paymentTimeout: 300,
autoVerify: true,
encryptionPublicKey: publicKey,
encryptionPrivateKey: privateKey,
});
// Public endpoint
app.get('/', (req, res) => {
res.json({
message: 'Welcome to X402 Payment API',
endpoints: {
free: '/api/free',
premium: '/api/premium-data',
analysis: '/api/premium-analysis',
},
});
});
// Free endpoint
app.get('/api/free', (req, res) => {
res.json({
message: 'This is a free endpoint',
data: {
timestamp: new Date().toISOString(),
value: Math.random() * 100,
},
});
});
// Premium endpoint
app.get(
'/api/premium-data',
paymentRequired({
amount: '0.01',
description: 'Access to premium data endpoint',
}),
(req, res) => {
res.json({
message: 'Premium data accessed successfully',
data: {
timestamp: new Date().toISOString(),
premiumValue: Math.random() * 1000,
secretData: 'This is premium content',
paymentId: req.payment?.paymentId,
},
});
}
);
// Premium analysis endpoint
app.post(
'/api/premium-analysis',
paymentRequired({
amount: '0.05',
description: 'Premium AI analysis service',
expiresIn: 600,
}),
async (req, res) => {
const { text } = req.body;
if (!text) {
return res.status(400).json({
error: 'Missing text field in request body',
});
}
// Simulate analysis
res.json({
message: 'Analysis completed',
input: text,
analysis: {
sentiment: 'positive',
wordCount: text.split(' ').length,
estimatedCost: '0.05 USDC',
paymentId: req.payment?.paymentId,
},
});
}
);
// Error handling
app.use(x402ErrorMiddleware());
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});Client Example
Complete client that makes payment-protected requests:
import { X402AutoClient } from '@shade402/client';
import { Keypair } from '@solana/web3.js';
async function fetchPremiumData() {
// Load wallet (in production, load from secure storage)
const wallet = Keypair.fromSecretKey(
Buffer.from(process.env.WALLET_SECRET_KEY!, 'base64')
);
// Create client
const client = new X402AutoClient(
wallet,
process.env.SOLANA_RPC_URL,
{
maxPaymentAmount: '1.0',
autoRetry: true,
}
);
try {
// Make request - payment handled automatically
const response = await client.get('https://api.example.com/premium-data');
console.log('Data received:', response.data);
return response.data;
} catch (error) {
console.error('Error:', error);
throw error;
} finally {
await client.close();
}
}
// Usage
fetchPremiumData().then(data => {
console.log('Success:', data);
});Explicit Client Example
Manual payment control with explicit client:
import { X402Client } from '@shade402/client';
import { Keypair } from '@solana/web3.js';
async function fetchWithManualPayment() {
const wallet = Keypair.generate();
const client = new X402Client(wallet, process.env.SOLANA_RPC_URL);
try {
// Make initial request
let response = await client.get('https://api.example.com/premium-data');
// Check if payment required
if (client.paymentRequired(response)) {
console.log('Payment required');
// Parse payment request
const paymentRequest = client.parsePaymentRequest(response);
console.log('Payment amount:', paymentRequest.maxAmountRequired);
// Check if expired
if (paymentRequest.isExpired()) {
throw new Error('Payment request expired');
}
// Create payment
console.log('Creating payment...');
const authorization = await client.createPayment(paymentRequest);
console.log('Payment created:', authorization.transactionHash);
// Encrypt resource if server public key available
let encryptedResource: string | undefined;
try {
encryptedResource = client.encryptResource(paymentRequest.resource);
} catch (error) {
// Encryption optional
}
// Retry with payment
response = await client.get('https://api.example.com/premium-data', {
payment: authorization,
encryptedResource,
});
}
// Process response
console.log('Data:', response.data);
return response.data;
} finally {
await client.close();
}
}LangChain Agent Example
LangChain agent with payment tool:
import { createX402PaymentTool } from '@shade402/langchain';
import { ChatOpenAI } from '@langchain/openai';
import { AgentExecutor, createOpenAIFunctionsAgent } from 'langchain/agents';
import { ChatPromptTemplate, MessagesPlaceholder } from '@langchain/core/prompts';
import { Keypair } from '@solana/web3.js';
async function createPaymentAgent() {
// Load wallet
const wallet = Keypair.fromSecretKey(
Buffer.from(process.env.WALLET_SECRET_KEY!, 'base64')
);
// Create payment tool
const paymentTool = createX402PaymentTool({
walletKeypair: wallet,
rpcUrl: process.env.SOLANA_RPC_URL,
maxPayment: '1.0',
name: 'x402_payment',
description: 'Make an X402 payment to access a paid API endpoint',
});
// Create prompt
const prompt = ChatPromptTemplate.fromMessages([
['system', 'You are a helpful assistant that can make payments for API access when needed.'],
['human', '{input}'],
new MessagesPlaceholder('agent_scratchpad'),
]);
// Create agent
const llm = new ChatOpenAI({ temperature: 0 });
const tools = [paymentTool];
const agent = await createOpenAIFunctionsAgent({
llm,
tools,
prompt,
});
const executor = new AgentExecutor({
agent,
tools,
verbose: true,
});
return executor;
}
// Usage
const agent = await createPaymentAgent();
const result = await agent.invoke({
input: 'Fetch premium data from https://api.example.com/premium-data and summarize it',
});
console.log(result.output);LangGraph Workflow Example
LangGraph workflow with payment nodes:
import { StateGraph } from '@langchain/langgraph';
import { fetchWithPaymentNode, PaymentState } from '@shade402/langgraph';
import { Keypair } from '@solana/web3.js';
function createPaymentWorkflow() {
const workflow = new StateGraph<PaymentState>({
channels: {
api_url: { reducer: (x, y) => y ?? x },
api_response: { reducer: (x, y) => y ?? x },
wallet_keypair: { reducer: (x, y) => y ?? x },
max_payment_amount: { reducer: (x, y) => y ?? x },
result: { reducer: (x, y) => y ?? x },
},
});
// Fetch API with automatic payment
workflow.addNode('fetch_api', fetchWithPaymentNode);
// Process response
workflow.addNode('process', async (state: PaymentState) => {
const data = JSON.parse(state.api_response || '{}');
return {
...state,
result: {
success: true,
data: data,
paymentId: data.paymentId,
},
};
});
// Error handler
workflow.addNode('error_handler', async (state: PaymentState) => {
return {
...state,
result: {
success: false,
error: state.payment_error,
},
};
});
workflow.setEntryPoint('fetch_api');
// Route based on result
workflow.addConditionalEdges(
'fetch_api',
(state: PaymentState) => {
if (state.payment_error) return 'error';
if (state.api_response) return 'success';
return 'error';
},
{
success: 'process',
error: 'error_handler',
}
);
return workflow.compile();
}
// Usage
const app = createPaymentWorkflow();
const wallet = Keypair.generate();
const result = await app.invoke({
api_url: 'https://api.example.com/premium-data',
wallet_keypair: wallet,
max_payment_amount: '1.0',
rpc_url: process.env.SOLANA_RPC_URL,
});
console.log(result.result);Next.js API Route Example
Next.js API route with payment protection:
// app/api/premium-data/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { withPayment, X402HandlerContext } from '@shade402/nextjs';
import { configureX402 } from '@/lib/x402-config';
configureX402();
export const GET = withPayment(
{
amount: '0.01',
description: 'Premium data access',
},
async (req: NextRequest, context: X402HandlerContext) => {
const payment = context.payment;
return NextResponse.json({
data: {
message: 'Premium data',
timestamp: new Date().toISOString(),
paymentId: payment?.paymentId,
},
});
}
);
export const POST = withPayment(
{
amount: '0.05',
description: 'Premium data write',
},
async (req: NextRequest, context: X402HandlerContext) => {
const body = await req.json();
const payment = context.payment;
// Process request
return NextResponse.json({
success: true,
processed: body,
paymentId: payment?.paymentId,
});
}
);Multiple Payment Tiers Example
Different payment tiers for different endpoints:
import express from 'express';
import { paymentRequired } from '@shade402/express';
const app = express();
// Free tier
app.get('/api/free', (req, res) => {
res.json({ tier: 'free', data: 'Free data' });
});
// Basic tier
app.get('/api/basic',
paymentRequired({ amount: '0.001', description: 'Basic tier access' }),
(req, res) => {
res.json({ tier: 'basic', data: 'Basic data' });
}
);
// Premium tier
app.get('/api/premium',
paymentRequired({ amount: '0.01', description: 'Premium tier access' }),
(req, res) => {
res.json({ tier: 'premium', data: 'Premium data' });
}
);
// Enterprise tier
app.get('/api/enterprise',
paymentRequired({ amount: '0.1', description: 'Enterprise tier access' }),
(req, res) => {
res.json({ tier: 'enterprise', data: 'Enterprise data' });
}
);Custom Verification Example
Custom payment verification logic:
import { paymentRequired, X402Request } from '@shade402/express';
import { verifyPaymentInDatabase } from './database';
app.post('/api/custom',
paymentRequired({
amount: '0.01',
autoVerify: false, // Disable automatic verification
}),
async (req: X402Request, res) => {
const payment = req.payment;
if (!payment) {
return res.status(402).json({ error: 'Payment required' });
}
// Custom verification against database
const isVerified = await verifyPaymentInDatabase(
payment.transactionHash
);
if (!isVerified) {
return res.status(403).json({ error: 'Payment not verified' });
}
// Process request
res.json({ success: true, paymentId: payment.paymentId });
}
);Error Handling Example
Comprehensive error handling:
import {
PaymentRequiredError,
PaymentExpiredError,
InsufficientFundsError,
} from '@shade402/core';
import { X402AutoClient } from '@shade402/client';
async function fetchWithErrorHandling() {
const client = new X402AutoClient(wallet, rpcUrl);
try {
const response = await client.get(url);
return response.data;
} catch (error) {
if (error instanceof PaymentRequiredError) {
console.log('Payment required:', error.paymentRequest);
// Handle payment required
} else if (error instanceof PaymentExpiredError) {
console.log('Payment expired');
// Handle expired payment
} else if (error instanceof InsufficientFundsError) {
console.log('Insufficient funds:', error.requiredAmount);
// Handle insufficient funds
} else {
console.error('Unexpected error:', error);
// Handle other errors
}
throw error;
} finally {
await client.close();
}
}Next Steps
Review Getting Started for setup
Check out Best Practices for guidelines
See Troubleshooting for common issues
Last updated
