SDK Documentation

@relai-fi/x402

Unified x402 payment SDK for Solana, Base, Polygon, Ethereum, Avalanche, and SKALE Base.

Multi-chainZero gas feesAuto-detect signingWorks out of the box

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.

Zero gas fees. The RelAI facilitator sponsors gas — users only pay for content (USDC). Works on all supported networks.

Installation

Terminal
npm install @relai-fi/x402

Quick Start — Client

Create a payment-aware fetch client. Works in the browser and Node.js:

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

const client = createX402Client({
  wallets: {
    solana: solanaWallet,  // @solana/wallet-adapter compatible
    evm: evmWallet,        // wagmi/viem compatible
  },
});

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

React Hook

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

PayButton.tsx
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

All networks use USDC with 6 decimals. Gas fees are sponsored by the RelAI facilitator.

NetworkIdentifier (v1)CAIP-2 (v2)Signing Method
Solanasolanasolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpSPL transfer + fee payer
Basebaseeip155:8453EIP-3009 transferWithAuthorization
Avalancheavalancheeip155:43114EIP-3009 transferWithAuthorization
Polygonpolygoneip155:137EIP-3009 transferWithAuthorization
Ethereumethereumeip155:1EIP-3009 transferWithAuthorization
SKALE Baseskale-baseeip155:1187947933EIP-3009 transferWithAuthorization

Both formats accepted. The SDK accepts v1 simple names (base, polygon) and v2 CAIP-2 identifiers (eip155:8453, eip155:137). Use networkV1ToV2() and networkV2ToV1() to convert between them.

createX402Client(config)

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

OptionTypeDefaultDescription
wallets{ solana?, evm? }{}Wallet adapters for each chain
facilitatorUrlstringRelAI facilitatorCustom facilitator endpoint
preferredNetworkRelaiNetworkPrefer this network when multiple accepts
solanaRpcUrlstringmainnet-betaSolana RPC endpoint
evmRpcUrlsRecord<string, string>Built-inRPC URLs per network name
maxAmountAtomicstringSafety cap on payment amount
verbosebooleanfalseLog payment flow to console

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 is the same as above.

PropertyTypeDescription
fetch(input, init?) => Promise<Response>Payment-aware fetch
isLoadingbooleanPayment in progress
status'idle' | 'pending' | 'success' | 'error'Current state
errorError | nullError details on failure
transactionIdstring | nullTx hash/signature on success
transactionUrlstring | nullBlock explorer link
transactionNetworkLabelstring | nullHuman-readable label (e.g. "Base")
connectedChains{ solana, evm }Which wallets are connected
reset() => voidReset state to idle

Server SDK (Express)

Protect any Express route with x402 micropayments:

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

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

// Protect any Express route with micropayments
app.get('/api/data', relai.protect({
  payTo: '0xYourWallet',
  price: 0.01,  // $0.01 USDC
  description: 'Premium data access',
}), (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',
}), handler);

req.payment

FieldTypeDescription
verifiedbooleanAlways true after settlement
transactionIdstringOn-chain transaction hash
payerstringPayer wallet address
networkstringNetwork name (e.g., base)
amountnumberPrice 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'

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

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';

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>   |                             |
RelAI© 2026 RelAI. Monetize APIs with x402 Protocol.