Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.swiftpay.finance/llms.txt

Use this file to discover all available pages before exploring further.

The @swiftpayfi/x402-node-guard middleware adds HTTP 402 payment requirements to your Express or Fastify routes. Protect specific endpoints with per-request stablecoin payments.

Features

  • Two-round payment flow — Return 402 + requirements, then serve on second request with payment
  • Express & Fastify support — Works with both frameworks
  • Server-agnostic signing — SwiftPay handles EIP-712 signature verification
  • No key management — Your server never touches private keys
  • Type-safe — Full TypeScript support

Installation

npm install @swiftpayfi/x402-node-guard @swiftpayfi/api-client

Quick Start

Express

import { SwiftPay } from '@swiftpayfi/api-client';
import { x402Express } from '@swiftpayfi/x402-node-guard/express';

const app = express();
const client = new SwiftPay({ secretKey: process.env.SWIFTPAY_SECRET_KEY });
const x402 = x402Express({ client });

app.get(
  '/v1/analyze',
  x402('https://api.example.com/v1/analyze'),
  (req, res) => {
    res.json({ sentiment: 'positive', score: 0.87 });
  }
);

Fastify

import { SwiftPay } from '@swiftpayfi/api-client';
import { x402Fastify } from '@swiftpayfi/x402-node-guard/fastify';

const fastify = Fastify();
const client = new SwiftPay({ secretKey: process.env.SWIFTPAY_SECRET_KEY });
const x402 = x402Fastify({ client });

fastify.get(
  '/v1/analyze',
  { preHandler: x402('https://api.example.com/v1/analyze') },
  async () => ({ sentiment: 'positive', score: 0.87 })
);

How It Works

The x402 payment flow is a two-round process:

Round 1: No Payment Header

Client makes a request without the X-PAYMENT header:
GET /v1/analyze
Server responds with HTTP 402 and payment requirements:
HTTP/1.1 402 Payment Required

{
  "x402-version": "v1",
  "x402-nonce": "...",
  "x402-payment-requirements": {
    "asset": "USDC",
    "network": "ethereum",
    "amount": "0.05",
    ...
  }
}

Round 2: With Payment Proof

Client signs the payment requirements and resends the request with the signed proof:
GET /v1/analyze
X-PAYMENT: <signed-eip712-payload>
Server validates the signature via SwiftPay’s API and serves the resource:
HTTP/1.1 200 OK

{
  "sentiment": "positive",
  "score": 0.87
}

Configuration

x402Express({
  client: SwiftPayClient,                    // Required: SwiftPay API client
  // Optional:
  baseUrl?: 'https://api.swiftpay.finance',  // API base URL
  timeout?: 30_000,                          // Request timeout in ms
});

Usage Patterns

Protect Single Route

app.get(
  '/api/premium-feature',
  x402('https://api.example.com/api/premium-feature'),
  (req, res) => {
    res.json({ data: 'exclusive content' });
  }
);

Protect Multiple Routes

const x402Guard = x402Express({ client });

app.get('/v1/analyze', x402Guard(...), handler1);
app.post('/v1/translate', x402Guard(...), handler2);
app.get('/v1/search', x402Guard(...), handler3);

Conditional Protection

app.get('/v1/feature', (req, res, next) => {
  // Require payment only for non-authenticated users
  if (req.headers.authorization) {
    return next(); // Skip x402
  }
  
  // Protect the route
  x402Guard('https://api.example.com/v1/feature')(req, res, next);
});

Error Handling

app.get(
  '/v1/analyze',
  x402('https://api.example.com/v1/analyze'),
  (req, res) => {
    try {
      const result = performAnalysis(req.body);
      res.json(result);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }
);

// Global error handler
app.use((err, req, res, next) => {
  if (err instanceof SwiftPayError) {
    return res.status(402).json({
      error: 'Payment required',
      details: err.message,
    });
  }
  next(err);
});

Client Implementation

Your frontend clients need to handle the 402 response and submit payment:
async function makePaymentRequest(url, options) {
  // First request
  let response = await fetch(url, options);
  
  if (response.status === 402) {
    // Extract payment requirements
    const requirements = JSON.parse(response.headers.get('x402-payment-requirements'));
    
    // User signs payment proof (using MetaMask, etc)
    const signature = await window.ethereum.request({
      method: 'eth_signTypedData_v4',
      params: [userAddress, JSON.stringify(requirements)],
    });
    
    // Second request with payment proof
    response = await fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        'X-PAYMENT': signature,
      },
    });
  }
  
  return response;
}

Full API Reference

For complete type definitions, advanced error handling, and additional patterns, see the official x402 Node Guard on NPM. All APIs are in v0.1.0-beta — stable and production-ready.