Examples
Real-world code examples for common use cases.
Node.js Backend Payment
Make payments from a Node.js backend using a private key:
import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import {
FacilitatorClient,
AgentPaymentClient,
FacilitatorError,
APECHAIN,
APECHAIN_USDC,
DEFAULT_FACILITATOR_URL,
DEFAULT_SETTLEMENT_ADDRESS,
toTokenUnits
} from '@x402apechain/sdk';
async function makePayment() {
// Setup wallet from private key
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const transport = http(APECHAIN.rpcUrls.default.http[0]);
const publicClient = createPublicClient({ chain: APECHAIN, transport });
const walletClient = createWalletClient({ account, chain: APECHAIN, transport });
// Create clients
const facilitator = new FacilitatorClient({
baseUrl: DEFAULT_FACILITATOR_URL,
chainId: APECHAIN.id,
settlementAddress: DEFAULT_SETTLEMENT_ADDRESS
});
const agent = new AgentPaymentClient({
facilitator,
publicClient,
walletClient
});
// Make payment
try {
const receipt = await agent.pay({
invoice: {
chainId: APECHAIN.id,
tokenAddress: APECHAIN_USDC,
recipient: '0xMerchantAddress...',
amount: toTokenUnits('5.00', 6) // 5 USDC
}
});
console.log('Payment successful!', receipt.txHash);
} catch (error) {
if (error instanceof FacilitatorError) {
if (error.isInsufficientFunds()) {
console.error('Not enough USDC balance');
} else {
console.error('Payment failed:', error.message);
}
}
}
}
makePayment();React Hook for Payments
A reusable React hook for making payments with wallet providers:
'use client';
import { useMemo, useCallback, useState } from 'react';
import { createPublicClient, createWalletClient, custom, http } from 'viem';
import {
FacilitatorClient,
AgentPaymentClient,
APECHAIN,
APECHAIN_USDC,
DEFAULT_FACILITATOR_URL,
DEFAULT_SETTLEMENT_ADDRESS,
toTokenUnits
} from '@x402apechain/sdk';
export function usePayment(walletProvider: any, account: string) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { agent } = useMemo(() => {
const publicClient = createPublicClient({
chain: APECHAIN,
transport: http()
});
const walletClient = createWalletClient({
account: account as `0x${string}`,
chain: APECHAIN,
transport: custom(walletProvider)
});
const facilitator = new FacilitatorClient({
baseUrl: DEFAULT_FACILITATOR_URL,
chainId: APECHAIN.id,
settlementAddress: DEFAULT_SETTLEMENT_ADDRESS
});
const agent = new AgentPaymentClient({
facilitator,
publicClient,
walletClient
});
return { agent };
}, [walletProvider, account]);
const pay = useCallback(async (
recipient: string,
amountUsdc: string
) => {
setLoading(true);
setError(null);
try {
const receipt = await agent.pay({
invoice: {
chainId: APECHAIN.id,
tokenAddress: APECHAIN_USDC,
recipient: recipient as `0x${string}`,
amount: toTokenUnits(amountUsdc, 6)
}
});
return receipt;
} catch (err) {
setError(err instanceof Error ? err.message : 'Payment failed');
throw err;
} finally {
setLoading(false);
}
}, [agent]);
return { pay, loading, error };
}Using the Hook
function PaymentButton({ recipient }: { recipient: string }) {
const { provider, address } = useWallet(); // Your wallet hook
const { pay, loading, error } = usePayment(provider, address);
const handlePay = async () => {
const receipt = await pay(recipient, '1.00');
alert(`Paid! TX: ${receipt.txHash}`);
};
return (
<button onClick={handlePay} disabled={loading}>
{loading ? 'Processing...' : 'Pay 1 USDC'}
</button>
);
}Express.js Payment Endpoint
Create a payment endpoint in an Express.js server:
import express from 'express';
import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import {
FacilitatorClient,
AgentPaymentClient,
APECHAIN,
APECHAIN_USDC,
toTokenUnits
} from '@x402apechain/sdk';
const app = express();
app.use(express.json());
// Initialize once at startup
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const transport = http();
const publicClient = createPublicClient({ chain: APECHAIN, transport });
const walletClient = createWalletClient({ account, chain: APECHAIN, transport });
const facilitator = new FacilitatorClient({
baseUrl: 'https://x402apes-production.up.railway.app',
chainId: APECHAIN.id,
settlementAddress: '0xe24a8dbf205ee116c991f60686f778a2337a844f'
});
const agent = new AgentPaymentClient({
facilitator,
publicClient,
walletClient
});
// Payment endpoint
app.post('/api/pay', async (req, res) => {
const { recipient, amount } = req.body;
try {
const receipt = await agent.pay({
invoice: {
id: `order-${Date.now()}`,
chainId: APECHAIN.id,
tokenAddress: APECHAIN_USDC,
recipient,
amount: toTokenUnits(amount, 6)
}
});
res.json({
success: true,
txHash: receipt.txHash,
settledAt: receipt.settledAt
});
} catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Payment failed'
});
}
});
app.listen(3000);Check Facilitator Health
Monitor the facilitator service status:
import { FacilitatorClient } from '@x402apechain/sdk';
const facilitator = new FacilitatorClient({
baseUrl: 'https://x402apes-production.up.railway.app',
chainId: 33139,
settlementAddress: '0xe24a8dbf205ee116c991f60686f778a2337a844f'
});
async function checkHealth() {
const health = await facilitator.health();
console.log('Status:', health.status);
console.log('Redis:', health.redis);
console.log('RPC:', health.rpc);
console.log('Time:', health.timestamp);
if (health.status !== 'ok') {
console.warn('Facilitator is not healthy!');
}
}
checkHealth();Get Transaction Stats
Fetch facilitator statistics for dashboards:
import { FacilitatorClient } from '@x402apechain/sdk';
const facilitator = new FacilitatorClient({
baseUrl: 'https://x402apes-production.up.railway.app',
chainId: 33139,
settlementAddress: '0xe24a8dbf205ee116c991f60686f778a2337a844f'
});
async function getStats() {
const stats = await facilitator.stats();
console.log('Total Transactions:', stats.totalTransactions);
console.log('Total Volume (USDC):', stats.totalVolumeUSDC);
console.log('Recent transactions:', stats.recent.length);
// Daily breakdown
for (const [date, data] of Object.entries(stats.daily)) {
console.log(`${date}: ${data.txs} txs, $${data.volume} USDC`);
}
}
getStats();More Examples
Check out the SDK package on npm for additional examples and the full source code.