npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nano-x402

v0.9.7

Published

x402 payment middleware for Express.js using Nano cryptocurrency - The first x402 implementation for Nano payments

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-x402

Quick 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

  1. Client requests your API without payment
  2. Server returns 402 with payment details (amount, Nano address, etc.)
  3. Client pays via Nano (instant, zero-fee transaction)
  4. Client retries with X-PAYMENT header containing transaction proof
  5. Server verifies payment via Xnoverse facilitator
  6. 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 address
  • routes (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/weather

Response (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:

  1. For testing: Use free tier with lower request volume
  2. For high-volume: Host your own x402 facilitator (see docs)
  3. 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