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

@relai-fi/x402

v0.5.18

Published

Unified x402 payment SDK for Solana, Base, Avalanche, SKALE Base, SKALE BITE, Polygon, and Ethereum. Automatic 402 handling with zero gas fees.

Readme


What is x402?

x402 is a protocol for HTTP-native micropayments. When a server returns HTTP 402 Payment Required, it includes payment details in the response. The client signs a payment, retries the request, and the server settles the payment and returns the protected content.

This SDK handles the entire flow automatically — call fetch() and payments happen transparently.


Why This SDK?

Multi-chain. Solana, Base, Avalanche, SKALE Base, SKALE Base Sepolia, SKALE BITE, Polygon, and Ethereum with a single API. Connect your wallets and the SDK picks the right chain and signing method automatically.

Zero gas fees. The RelAI facilitator sponsors gas — users only pay for content (USDC).

Auto-detects signing method. EIP-3009 transferWithAuthorization for all supported EVM networks and native SPL transfer for Solana, all handled internally.

Works out of the box. Uses the RelAI facilitator by default.


Examples

Try a live end-to-end flow in the RelAI Playground:


Quick Start

Install

npm install @relai-fi/x402

Client (Browser / Node.js)

import { createX402Client } from '@relai-fi/x402/client';

const client = createX402Client({
  wallets: {
    solana: solanaWallet,  // @solana/wallet-adapter compatible
    evm: evmWallet,        // wagmi/viem compatible
  },
  preferredNetwork: 'base',
  // default: 'prefer_then_any'
  // - prefer_then_any: try preferred network, then any payable wallet/network
  // - strict_preferred: fail if preferred network isn't payable with connected wallets
  networkSelectionMode: 'prefer_then_any',
  integritas: {
    enabled: true,
    flow: 'single', // or 'dual'
  },
  relayWs: {
    enabled: true,
    // optional: explicit WS endpoint
    // wsUrl: 'wss://api.relai.fi/api/ws/relay',
  },
});

// 402 responses are handled automatically
const response = await client.fetch('https://api.example.com/protected');
const data = await response.json();

Preferred network behavior

If the 402 challenge contains multiple accepts networks:

  • networkSelectionMode: 'prefer_then_any' (default) tries preferredNetwork first, then falls back to any payable option.
  • networkSelectionMode: 'strict_preferred' only allows the preferred network and throws if it's not payable with connected wallets.
const client = createX402Client({
  wallets: { evm: evmWallet },
  preferredNetwork: 'solana',
  networkSelectionMode: 'strict_preferred',
});

// Throws if only Solana accept is preferred but no Solana wallet is connected.
await client.fetch('https://api.example.com/protected');

Integritas (client)

createX402Client can set Integritas headers automatically for every request.

const client = createX402Client({
  wallets: { evm: evmWallet },
  integritas: {
    enabled: true,
    flow: 'single',
  },
});

// Sends:
// X-Integritas: true
// X-Integritas-Flow: single
await client.fetch('https://api.relai.fi/relay/<apiId>/v1/chat/completions');

// Per-request override
await client.fetch('https://api.relai.fi/relay/<apiId>/v1/chat/completions', {
  method: 'POST',
  x402: {
    integritas: { enabled: true, flow: 'dual' },
  },
});

WebSocket relay transport (optional)

If your protected API is behind a relay URL like https://api.relai.fi/relay/:apiId/... or a whitelabel relay URL like https://<whitelabel>.x402.fi/..., the SDK can use the Relay WebSocket transport automatically.

const client = createX402Client({
  wallets: {
    evm: evmWallet,
  },
  relayWs: {
    enabled: true,
    preflightTimeoutMs: 5000,
    paymentTimeoutMs: 10000,
    fallbackToHttp: true,
  },
});

// Pass your standard relay HTTP URL (apiId-based or whitelabel-based).
// SDK handles WS preflight + paid retry internally.
await client.fetch('https://api.relai.fi/relay/1769629274857/v1/chat/completions', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ messages: [{ role: 'user', content: 'Hello' }] }),
});

// Whitelabel relay URL is also supported.
await client.fetch('https://tgmetrics.x402.fi/projects?page=1', {
  method: 'GET',
});

For Node.js runtimes without global WebSocket, provide relayWs.webSocketFactory.

If the relay returns multiple accepts options for one request, the SDK automatically falls back to standard HTTP x402 flow for that call.

React Hook

Works with @solana/wallet-adapter-react and wagmi:

import { useRelaiPayment } from '@relai-fi/x402/react';
import { useWallet } from '@solana/wallet-adapter-react';
import { useAccount, useSignTypedData } from 'wagmi';

function PayButton() {
  const solanaWallet = useWallet();
  const { address } = useAccount();
  const { signTypedDataAsync } = useSignTypedData();

  const {
    fetch,
    isLoading,
    status,
    transactionUrl,
    transactionNetworkLabel,
  } = useRelaiPayment({
    wallets: {
      solana: solanaWallet,
      evm: address ? { address, signTypedData: signTypedDataAsync } : undefined,
    },
  });

  return (
    <div>
      <button onClick={() => fetch('/api/protected')} disabled={isLoading}>
        {isLoading ? 'Paying...' : 'Access API'}
      </button>
      {transactionUrl && (
        <a href={transactionUrl} target="_blank">
          View on {transactionNetworkLabel}
        </a>
      )}
    </div>
  );
}

Supported Networks

| Network | Identifier | CAIP-2 | Signing Method | USDC Contract | |---------|-----------|--------|----------------|---------------| | Solana | solana | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | SPL transfer + fee payer | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | | Base | base | eip155:8453 | EIP-3009 transferWithAuthorization | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 | | Avalanche | avalanche | eip155:43114 | EIP-3009 transferWithAuthorization | 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E | | SKALE Base | skale-base | eip155:1187947933 | EIP-3009 transferWithAuthorization | 0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20 | | SKALE Base Sepolia | skale-base-sepolia | eip155:324705682 | EIP-3009 transferWithAuthorization | 0x2e08028E3C4c2356572E096d8EF835cD5C6030bD | | SKALE BITE | skale-bite | eip155:103698795 | EIP-3009 transferWithAuthorization | 0xc4083B1E81ceb461Ccef3FDa8A9F24F0d764B6D8 | | Polygon | polygon | eip155:137 | EIP-3009 transferWithAuthorization | 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 | | Ethereum | ethereum | eip155:1 | EIP-3009 transferWithAuthorization | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 |

All networks support USDC (6 decimals). On SKALE Base networks, the SDK also supports:

  • SKALE Base (skale-base): USDT (0x2bF5bF154b515EaA82C31a65ec11554fF5aF7fCA), WBTC (0x1aeeCFE5454c83B42D8A316246CAc9739E7f690e), WETH (0x7bD39ABBd0Dd13103542cAe3276C7fA332bCA486)
  • SKALE Base Sepolia (skale-base-sepolia): USDT (0x3ca0a49f511c2c89c4dcbbf1731120d8919050bf), WBTC (0x4512eacd4186b025186e1cf6cc0d89497c530e87), WETH (0xf94056bd7f6965db3757e1b145f200b7346b4fc0)

Gas fees are sponsored by the RelAI facilitator.


Package Exports

// Client — browser & Node.js fetch wrapper with automatic 402 handling
import { createX402Client } from '@relai-fi/x402/client';

// React hook — state management + wallet integration
import { useRelaiPayment } from '@relai-fi/x402/react';

// Server — Express middleware for protecting endpoints
import Relai from '@relai-fi/x402/server';

// Utilities — payload conversion, unit helpers
import {
  convertV1ToV2,
  convertV2ToV1,
  networkV1ToV2,
  networkV2ToV1,
  toAtomicUnits,
  fromAtomicUnits,
} from '@relai-fi/x402/utils';

// Types & constants
import {
  RELAI_NETWORKS,
  CHAIN_IDS,
  USDC_ADDRESSES,
  NETWORK_CAIP2,
  EXPLORER_TX_URL,
  type RelaiNetwork,
  type SolanaWallet,
  type EvmWallet,
  type WalletSet,
} from '@relai-fi/x402';

API Reference

createX402Client(config)

Creates a fetch wrapper that automatically handles 402 Payment Required responses.

| Option | Type | Default | Description | |--------|------|---------|-------------| | wallets | { solana?, evm? } | {} | Wallet adapters for each chain | | relayWs | X402RelayWsConfig | undefined | Optional WS transport for relay URLs | | integritas | boolean \| X402IntegritasConfig | undefined | Automatically set Integritas headers | | facilitatorUrl | string | RelAI facilitator | Custom facilitator endpoint | | preferredNetwork | RelaiNetwork | — | Prefer this network when multiple accepts | | networkSelectionMode | 'prefer_then_any' \| 'strict_preferred' | 'prefer_then_any' | Selection policy for preferredNetwork when multiple accepts are returned | | solanaRpcUrl | string | https://api.mainnet-beta.solana.com | Solana RPC (use Helius/Quicknode for production) | | evmRpcUrls | Record<string, string> | Built-in defaults | RPC URLs per network name | | maxAmountAtomic | string | — | Safety cap on payment amount | | verbose | boolean | false | Log payment flow to console |

integritas options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | enabled | boolean | true when object is provided | Adds X-Integritas: true | | flow | 'single' \| 'dual' | — | Adds X-Integritas-Flow |

relayWs options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | enabled | boolean | false | Enable WS transport for relay URLs | | wsUrl | string | derived from relay host | Explicit WebSocket relay endpoint | | preflightTimeoutMs | number | 5000 | Timeout for WS preflight request | | paymentTimeoutMs | number | 10000 | Timeout for paid WS retry | | fallbackToHttp | boolean | true | Fall back to standard HTTP flow if WS fails | | webSocketFactory | (url) => WebSocketLike | runtime WebSocket | Custom WS factory for Node.js/server runtimes |

Wallet interfaces:

// Solana — compatible with @solana/wallet-adapter-react useWallet()
interface SolanaWallet {
  publicKey: { toString(): string } | null;
  signTransaction: ((tx: unknown) => Promise<unknown>) | null;
}

// EVM — pass address + signTypedData from wagmi
interface EvmWallet {
  address: string;
  signTypedData: (params: {
    domain: Record<string, unknown>;
    types: Record<string, unknown[]>;
    message: Record<string, unknown>;
    primaryType: string;
  }) => Promise<string>;
}

useRelaiPayment(config)

React hook wrapping createX402Client with state management.

Config — same as createX402Client (see above).

Returns:

| Property | Type | Description | |----------|------|-------------| | fetch | (input, init?) => Promise<Response> | Payment-aware fetch | | isLoading | boolean | Payment in progress | | status | 'idle' \| 'pending' \| 'success' \| 'error' | Current state | | error | Error \| null | Error details on failure | | transactionId | string \| null | Tx hash/signature on success | | transactionNetwork | RelaiNetwork \| null | Network used for payment | | transactionNetworkLabel | string \| null | Human-readable label (e.g. "Base") | | transactionUrl | string \| null | Block explorer link | | connectedChains | { solana: boolean, evm: boolean } | Which wallets are connected | | isConnected | boolean | Any wallet connected | | reset | () => void | Reset state to idle |


Server SDK (Express)

import Relai from '@relai-fi/x402/server';

const relai = new Relai({
  network: 'base', // or 'solana', 'avalanche', 'skale-base', 'skale-base-sepolia', ...
});

// Protect any Express route with micropayments
app.get('/api/data', relai.protect({
  payTo: '0xYourWallet',
  price: 0.01,  // $0.01 USDC
  description: 'Premium data access',
  integritas: {
    enabled: true,
    flow: 'single',
  },
}), (req, res) => {
  // req.payment = { verified, transactionId, payer, network, amount }
  res.json({ data: 'Protected content', payment: req.payment });
});

// Dynamic pricing
app.get('/api/premium', relai.protect({
  payTo: '0xYourWallet',
  price: (req) => req.query.tier === 'pro' ? 0.10 : 0.01,
}), handler);

// Per-endpoint network override
app.get('/api/solana-data', relai.protect({
  payTo: 'SolanaWalletAddress',
  price: 0.005,
  network: 'solana', // overrides the default 'base'
}), handler);

Flow:

  1. Request without payment → 402 with accepts array
  2. Client signs payment (SDK handles this) → retries with X-PAYMENT header
  3. Server calls RelAI facilitator /settle → gas sponsored by RelAI
  4. Settlement success → PAYMENT-RESPONSE header set, req.payment populated, next() called

Integritas on server protect:

  • integritas: true enables Integritas metadata for the endpoint.
  • integritas: { enabled: true, flow: 'single' } sets default flow.
  • Buyer headers (X-Integritas, X-Integritas-Flow) override defaults per request.

req.payment fields: | Field | Type | Description | |-------|------|-------------| | verified | boolean | Always true after settlement | | transactionId | string | On-chain transaction hash | | payer | string | Payer wallet address | | network | string | Network name (e.g., base) | | amount | number | Price in USD |


Utilities

import { toAtomicUnits, fromAtomicUnits } from '@relai-fi/x402/utils';

toAtomicUnits(0.05, 6);       // '50000'   ($0.05 USDC)
toAtomicUnits(1.50, 6);       // '1500000' ($1.50 USDC)

fromAtomicUnits('50000', 6);  // 0.05
fromAtomicUnits('1500000', 6); // 1.5

Payload Conversion (v1 ↔ v2)

import { convertV1ToV2, convertV2ToV1, networkV1ToV2 } from '@relai-fi/x402/utils';

networkV1ToV2('solana');     // 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'
networkV1ToV2('base');       // 'eip155:8453'
networkV1ToV2('avalanche');  // 'eip155:43114'
networkV1ToV2('skale-base'); // 'eip155:1187947933'
networkV1ToV2('skale-base-sepolia'); // 'eip155:324705682'

const v2Payload = convertV1ToV2(v1Payload);
const v1Payload = convertV2ToV1(v2Payload);

How It Works

Client                        Server                     Facilitator
  |                             |                             |
  |── GET /api/data ──────────>|                             |
  |<── 402 Payment Required ───|                             |
  |   (accepts: network, amount, asset)                      |
  |                             |                             |
  | SDK signs payment           |                             |
  | (EIP-3009/SPL)              |                             |
  |                             |                             |
  |── GET /api/data ──────────>|                             |
  |   X-PAYMENT: <signed>      |── settle ─────────────────>|
  |                             |<── tx hash ────────────────|
  |<── 200 OK + data ─────────|                             |
  |   PAYMENT-RESPONSE: <tx>   |                             |

Development

npm run build        # Build ESM + CJS bundles
npm run dev          # Watch mode
npm run type-check   # TypeScript checks
npm test             # Run tests

License

MIT