ReferenceServer Middleware

Server Middleware

HTTP server middleware packages for integrating T402 payment requirements into your backend.

Express.js middleware for protecting routes with t402 payment requirements. Automatically handles payment verification, settlement, and paywall rendering.

Installation

npm install @t402/express @t402/core

Quick Start

import express from 'express';
import { paymentMiddleware } from '@t402/express';
import { t402ResourceServer, createFacilitatorClient } from '@t402/core/server';
import { registerExactEvmScheme } from '@t402/evm/exact/server';
 
const app = express();
 
// Create and configure the t402 server
const facilitator = createFacilitatorClient({ url: 'https://facilitator.t402.io' });
const server = new t402ResourceServer(facilitator);
registerExactEvmScheme(server, {});
 
// Define protected routes
const routes = {
  '/api/premium/*': {
    accepts: {
      scheme: 'exact',
      network: 'eip155:8453',
      payTo: '0xYourAddress',
      price: '$0.01',
    },
    description: 'Premium API access',
  },
};
 
// Apply middleware
app.use(paymentMiddleware(routes, server));
 
// Protected route
app.get('/api/premium/data', (req, res) => {
  res.json({ data: 'Premium content' });
});
 
app.listen(3000);

API Reference

paymentMiddleware

Creates Express middleware with a pre-configured server instance.

function paymentMiddleware(
  routes: RoutesConfig,
  server: t402ResourceServer,
  paywallConfig?: PaywallConfig,
  paywall?: PaywallProvider,
  syncFacilitatorOnStart?: boolean
): RequestHandler

Parameters

ParameterTypeDescription
routesRoutesConfigRoute configurations for protected endpoints
servert402ResourceServerPre-configured server instance
paywallConfigPaywallConfigOptional paywall UI configuration
paywallPaywallProviderOptional custom paywall provider
syncFacilitatorOnStartbooleanSync with facilitator on startup (default: true)

Example

import { paymentMiddleware } from '@t402/express';
import { t402ResourceServer } from '@t402/core/server';
 
const server = new t402ResourceServer(facilitatorClient);
registerExactEvmScheme(server, {});
 
app.use(paymentMiddleware(routes, server, {
  title: 'Premium Content',
  description: 'Pay to access this resource',
}));

paymentMiddlewareFromConfig

Creates Express middleware with simple configuration (server created internally).

function paymentMiddlewareFromConfig(
  routes: RoutesConfig,
  facilitatorClients?: FacilitatorClient | FacilitatorClient[],
  schemes?: SchemeRegistration[],
  paywallConfig?: PaywallConfig,
  paywall?: PaywallProvider,
  syncFacilitatorOnStart?: boolean
): RequestHandler

Parameters

ParameterTypeDescription
routesRoutesConfigRoute configurations for protected endpoints
facilitatorClientsFacilitatorClient | FacilitatorClient[]Facilitator client(s) for payment processing
schemesSchemeRegistration[]Array of scheme registrations
paywallConfigPaywallConfigOptional paywall UI configuration
paywallPaywallProviderOptional custom paywall provider
syncFacilitatorOnStartbooleanSync with facilitator on startup (default: true)

Example

import { paymentMiddlewareFromConfig } from '@t402/express';
import { createExactEvmServer } from '@t402/evm/exact/server';
 
app.use(paymentMiddlewareFromConfig(
  routes,
  facilitatorClient,
  [{ network: 'eip155:8453', server: createExactEvmServer({}) }],
  { title: 'Premium Content' }
));

Route Configuration

RoutesConfig

Define which routes require payment and their pricing:

const routes: RoutesConfig = {
  // Single price for route
  '/api/premium/*': {
    accepts: {
      scheme: 'exact',
      network: 'eip155:8453',
      payTo: '0xRecipient',
      price: '$0.01',
    },
    description: 'Premium API access',
  },
 
  // Multiple payment options
  '/api/multi-chain/*': {
    accepts: [
      {
        scheme: 'exact',
        network: 'eip155:8453',
        payTo: '0xRecipient',
        price: '$0.01',
      },
      {
        scheme: 'exact',
        network: 'ton:mainnet',
        payTo: 'EQRecipientAddress',
        price: '$0.01',
      },
    ],
    description: 'Multi-chain payment support',
  },
 
  // With extensions
  '/api/bazaar/*': {
    accepts: {
      scheme: 'exact',
      network: 'eip155:8453',
      payTo: '0xRecipient',
      price: '$0.01',
    },
    description: 'Dynamic pricing endpoint',
    extensions: {
      bazaar: {
        endpoint: 'https://api.example.com/bazaar',
      },
    },
  },
};

PaywallConfig

Configure the built-in paywall UI:

interface PaywallConfig {
  title?: string;
  description?: string;
  logoUrl?: string;
  theme?: 'light' | 'dark' | 'auto';
  customCss?: string;
}

Example

const paywallConfig: PaywallConfig = {
  title: 'Premium API',
  description: 'Pay once to access this endpoint',
  logoUrl: 'https://example.com/logo.png',
  theme: 'dark',
};
 
app.use(paymentMiddleware(routes, server, paywallConfig));

Multi-Network Support

Accept payments from multiple blockchain networks:

import { registerExactEvmScheme } from '@t402/evm/exact/server';
import { registerExactTonScheme } from '@t402/ton/exact/server';
import { registerExactSvmScheme } from '@t402/svm/exact/server';
 
const server = new t402ResourceServer(facilitator);
 
// Register multiple networks
registerExactEvmScheme(server, {}); // All EVM chains
registerExactTonScheme(server, {}); // TON
registerExactSvmScheme(server, {}); // Solana
 
const routes = {
  '/api/data': {
    accepts: [
      { scheme: 'exact', network: 'eip155:8453', payTo: '0x...', price: '$0.01' },
      { scheme: 'exact', network: 'ton:mainnet', payTo: 'EQ...', price: '$0.01' },
      { scheme: 'exact', network: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', payTo: '8GG...', price: '$0.01' },
    ],
    description: 'Multi-chain endpoint',
  },
};
 
app.use(paymentMiddleware(routes, server));

Settlement Behavior

The middleware handles settlement atomically:

  1. Request received - Middleware checks if route requires payment
  2. Payment verified - Signature is validated before proceeding
  3. Handler executes - Your route handler runs
  4. Settlement on success - Payment is settled only if handler returns status < 400
  5. Response sent - Settlement confirmation headers are added
app.get('/api/premium/data', (req, res) => {
  try {
    const data = fetchPremiumData();
    res.json({ data }); // Status 200 -> Payment settles
  } catch (error) {
    res.status(500).json({ error: 'Failed' }); // Status 500 -> No settlement
  }
});

Settlement only occurs after your handler returns a successful response (status < 400). If your handler throws an error or returns a 4xx/5xx status, the payment is not settled.

Error Handling

The middleware returns structured error responses:

// 402 - Payment Required
{
  "error": "Payment required",
  "paymentRequirements": { ... }
}
 
// 402 - Settlement Failed
{
  "error": "Settlement failed",
  "details": "Insufficient balance"
}

Custom Paywall Provider

Implement a custom paywall for branded experiences:

import { PaywallProvider } from '@t402/core/server';
 
const customPaywall: PaywallProvider = {
  render: (paymentRequired, config) => {
    return `
      <!DOCTYPE html>
      <html>
        <head><title>${config?.title || 'Payment Required'}</title></head>
        <body>
          <h1>Custom Paywall</h1>
          <p>Amount: ${paymentRequired.requirements[0].maxAmountRequired}</p>
          <button onclick="handlePayment()">Pay Now</button>
        </body>
      </html>
    `;
  },
};
 
app.use(paymentMiddleware(routes, server, paywallConfig, customPaywall));

Type Exports

// Server types
export { t402ResourceServer, t402HTTPResourceServer } from '@t402/core/server';
export type { PaywallProvider, PaywallConfig } from '@t402/core/server';
export { RouteConfigurationError } from '@t402/core/server';
export type { RouteValidationError } from '@t402/core/server';
 
// Protocol types
export type {
  PaymentRequired,
  PaymentRequirements,
  PaymentPayload,
  Network,
  SchemeNetworkServer,
} from '@t402/core/types';
 
// Adapter
export { ExpressAdapter } from '@t402/express';