nano-x402
v0.9.7
Published
x402 payment middleware for Express.js using Nano cryptocurrency - The first x402 implementation for Nano payments
Maintainers
Readme
x402-nano
The first x402 payment middleware for Nano cryptocurrency 🎉
Add instant, zero-fee cryptocurrency payments to your Express.js API using the x402 HTTP payment protocol and Nano.
Features
✅ Standards-based - Uses official HTTP 402 Payment Required
✅ Instant payments - Nano transactions confirm in 350 ms
✅ Zero fees - No transaction fees on Nano network
✅ Simple integration - Add payments with 3 lines of code
✅ Bot-friendly - Works with AI agents and automated clients
✅ TypeScript support - Full type definitions included
✅ Replay attack protection - Tracks processed transactions to prevent reuse
✅ Timeout handling - 10-second timeout for facilitator verification
✅ Comprehensive validation - Full X-PAYMENT header validation
Installation
npm install nano-x402Quick Start
import express from 'express';
import { paymentMiddleware } from 'nano-x402';
const app = express();
// Add payment middleware
app.use(paymentMiddleware(
'nano_your_wallet_address_here',
{
'GET /api/weather': {
price: '0.01',
description: 'Get weather data'
},
'POST /api/analyze': {
price: '0.05',
description: 'Analyze data'
}
}
));
// Your routes work as normal
app.get('/api/weather', (req, res) => {
res.json({
temperature: 72,
conditions: 'sunny'
});
});
app.post('/api/analyze', (req, res) => {
res.json({
result: 'analysis complete'
});
});
app.listen(3000);That's it! Your API now accepts Nano payments via x402 protocol.
How It Works
- Client requests your API without payment
- Server returns 402 with payment details (amount, Nano address, etc.)
- Client pays via Nano (instant, zero-fee transaction)
- Client retries with X-PAYMENT header containing transaction proof
- Server verifies payment via Xnoverse facilitator
- Server returns the data ✅
Configuration Options
app.use(paymentMiddleware(
'nano_your_address',
{
// Route configuration
'GET /paid-endpoint': {
price: '0.01', // Price in XNO (required)
description: 'Endpoint description', // Optional
id: 'unique-id', // Optional
type: 'api-endpoint' // Optional
}
},
{
// Middleware options
facilitator: 'https://xnoverse.com/api/x402', // Default facilitator
freeRoutes: ['GET /health'], // Routes that don't require payment
// Called when payment is received
onPaymentReceived: async (payment, req, res) => {
console.log('Payment received:', payment.hash);
// Log to database, analytics, etc.
}
}
));API Reference
paymentMiddleware(recipientAddress, routes, options)
Main middleware function.
Parameters:
recipientAddress(string) - Your Nano wallet addressroutes(object) - Route configurations keyed by "METHOD /path"options(object) - Optional configuration
Returns: Express middleware function
hasValidPayment(req)
Check if request has verified payment.
app.get('/api/data', (req, res) => {
if (hasValidPayment(req)) {
// Payment verified
res.json({ data: 'premium content' });
}
});getPaymentInfo(req)
Get payment details from request.
app.get('/api/data', (req, res) => {
const payment = getPaymentInfo(req);
console.log('Paid by:', payment.sender);
console.log('Amount:', payment.amount, 'XNO');
console.log('TX Hash:', payment.hash);
});Examples
Basic Weather API
import express from 'express';
import { paymentMiddleware } from 'nano-x402';
const app = express();
app.use(paymentMiddleware(
'nano_1abc...',
{
'GET /weather/:city': { price: '0.001' }
}
));
app.get('/weather/:city', (req, res) => {
res.json({
city: req.params.city,
temperature: 72,
conditions: 'sunny'
});
});
app.listen(3000);AI Agent API
app.use(paymentMiddleware(
'nano_1abc...',
{
'POST /ai/generate': {
price: '0.1',
description: 'Generate AI content'
}
},
{
onPaymentReceived: async (payment) => {
await logToDatabase({
txHash: payment.hash,
amount: payment.amount,
sender: payment.sender
});
}
}
));
app.post('/ai/generate', (req, res) => {
const result = generateAIContent(req.body.prompt);
res.json({ result });
});Multiple Endpoints
app.use(paymentMiddleware(
'nano_1abc...',
{
'GET /basic-data': { price: '0.01' },
'GET /premium-data': { price: '0.05' },
'POST /process': { price: '0.10' },
'GET /expensive-computation': { price: '1.0' }
},
{
freeRoutes: [
'GET /health',
'GET /status',
'GET /docs'
]
}
));Real-World Example
Here's a complete example accessing an actual Xnoverse paywall:
// Access paywall OKbeWNy0HhiQgi from xnoverse.com
const paywallKey = 'OKbeWNy0HhiQgi';
// 1. Request content (will get 402)
const response = await fetch(`https://xnoverse.com/api/paywall/${paywallKey}`);
console.log(`Status: ${response.status}`); // 402 Payment Required
const payment402 = await response.json();
console.log(`Price: ${payment402.payment.amount} XNO`);
console.log(`Pay to: ${payment402.payment.recipient}`);
// 2. Send Nano payment (using your Nano wallet)
const txHash = await sendNano(
payment402.payment.recipient,
payment402.payment.amount_raw
);
// 3. Create X-PAYMENT header
const xPayment = Buffer.from(JSON.stringify({
hash: txHash,
sender: 'nano_your_address',
recipient: payment402.payment.recipient,
amount: payment402.payment.amount,
amount_raw: payment402.payment.amount_raw
})).toString('base64');
// 4. Retry with payment
const contentResponse = await fetch(
`https://xnoverse.com/api/paywall/${paywallKey}`,
{ headers: { 'X-Payment': xPayment } }
);
console.log(`Status: ${contentResponse.status}`); // 200 OK
const content = await contentResponse.json();
console.log('Content:', content); // Your unlocked content!Testing
Make a request without payment:
curl http://localhost:3000/api/weatherResponse (402 Payment Required):
{
"version": "x402-nano-v1",
"network": "nano",
"payment": {
"amount": "0.01",
"amount_raw": "10000000000000000000000000000",
"currency": "XNO",
"recipient": "nano_1abc...",
"uri": "nano:nano_1abc...?amount=10000000000000000000000000000"
},
"resource": {
"endpoint": "http://localhost:3000/api/weather",
"method": "GET",
"price": "0.01",
"currency": "XNO"
},
"facilitator": {
"verify_url": "https://xnoverse.com/api/x402/verify",
"settle_url": "https://xnoverse.com/api/x402/settle"
}
}How Clients Pay
Clients use the x402 protocol to pay:
// 1. Get payment requirements
const response = await fetch('http://localhost:3000/api/weather');
const payment402 = await response.json();
// 2. Pay via Nano (creates transaction on network)
const txHash = await sendNano(
payment402.payment.recipient,
payment402.payment.amount_raw
);
// 3. Retry with payment proof
const xPayment = Buffer.from(JSON.stringify({
hash: txHash,
sender: 'nano_your_address',
recipient: payment402.payment.recipient,
amount: payment402.payment.amount,
amount_raw: payment402.payment.amount_raw
})).toString('base64');
const data = await fetch('http://localhost:3000/api/weather', {
headers: { 'X-Payment': xPayment }
});Facilitator
This middleware uses the Xnoverse Nano Facilitator by default to verify payments. The facilitator:
- Verifies Nano transactions on-chain
- Checks payment amounts
- Validates signatures
- Returns verification instantly
You can use the public facilitator at https://xnoverse.com/api/x402 (free) or run your own.
Security Features
Replay Attack Protection
Prevents the same payment from being used multiple times. The middleware tracks processed transaction hashes with automatic cleanup of old entries.
Timeout Handling
Facilitator verification calls have a 10-second timeout to prevent requests from hanging indefinitely.
Comprehensive Validation
- All required X-PAYMENT header fields are validated
- Transaction hash format validation (256-bit hex)
- Nano address format validation
- HTTP response status checking
Error Handling
Distinguishes between:
- Validation failures (invalid payment) → 402 Payment Required
- Infrastructure errors (facilitator down) → 503 Service Unavailable
- Timeout errors → Clear error message
Rate Limiting
The Xnoverse Facilitator implements rate limiting to protect infrastructure and ensure fair usage:
Free Tier (default):
- ✅ 10 requests per hour
- ✅ 100 requests per day
- ✅ No license required
- ✅ Perfect for testing and low-volume APIs
Example: Rate Limited Response (429 Too Many Requests):
{
"valid": false,
"error": "Rate limit exceeded. Free tier: 10 requests/hour, 100/day.",
"version": "x402-nano-v1",
"rate_limit": {
"remaining_hour": 0,
"remaining_day": 0,
"reset_at": "2025-11-15T00:00:00.000Z"
}
}Response Headers:
X-RateLimit-Limit-Hour: 10
X-RateLimit-Remaining-Hour: 5
X-RateLimit-Limit-Day: 100
X-RateLimit-Remaining-Day: 75
X-RateLimit-Reset: 2025-11-15T00:00:00.000Z (when limited)If you hit rate limits:
- For testing: Use free tier with lower request volume
- For high-volume: Host your own x402 facilitator (see docs)
- For AI agents: Cache results to reduce API calls
See x402 Facilitator Rate Limits Documentation for detailed information.
Why Nano?
- ⚡ Instant - Transactions confirm in 350 ms
- 💰 Zero fees - No transaction costs ever
- 🌍 Eco-friendly - Minimal energy usage
- 🔐 Secure - Battle-tested blockchain
- 💡 Experience Nano yourself - Try it now
Requirements
- Node.js 16+
- Express 4.x or 5.x
- Nano wallet address
License
MIT
Links
- Documentation: https://xnoverse.com/docs/x402
- Xnoverse Facilitator: https://xnoverse.com/api/x402/info
- x402 Protocol: https://docs.cdp.coinbase.com/x402
- Nano: https://nano.org
Support
Questions? Issues? Ideas?
- Discord: https://discord.com/invite/EYEh7kwKRu
Made with ❤️ for the Nano and x402 communities
