New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@payai/x402-solana

Package Overview
Dependencies
Maintainers
3
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@payai/x402-solana

A framework-agnostic implementation of the x402 payment protocol v2 for Solana clients (browsers) and servers

latest
Source
npmnpm
Version
2.0.0
Version published
Maintainers
3
Created
Source

x402-solana

A reusable, framework-agnostic implementation of the x402 payment protocol v2 for Solana clients (browsers) and servers.

Features

x402 Protocol v2 - Full support for the latest x402 v2 specification
CAIP-2 Networks - Uses standardized chain identifiers (solana:chainId)
Client-side - Automatic 402 payment handling with any wallet provider
Server-side - Payment verification and settlement with facilitator
Framework agnostic - Works with any wallet provider (Privy, Phantom, etc.)
HTTP framework agnostic - Works with Next.js, Express, Fastify, etc.
TypeScript - Full type safety with Zod validation
Web3.js - Built on @solana/web3.js and @solana/spl-token

Installation

pnpm add @payai/x402-solana

Or with npm:

npm install @payai/x402-solana

Or with yarn:

yarn add @payai/x402-solana

x402 Protocol v2

This package implements x402 protocol v2. Key features:

Featurev2 Specification
Network FormatCAIP-2 (solana:chainId)
Payment HeaderPAYMENT-SIGNATURE
Amount Fieldamount
Payload StructureIncludes resource and accepted fields
Response BodyPaymentRequired with x402Version: 2

Usage

Client Side (React/Frontend)

The x402-solana client works with any wallet provider that implements the WalletAdapter interface. Below are examples using both Solana Wallet Adapter and Privy.

First, install the required packages:

npm install @solana/wallet-adapter-react @solana/wallet-adapter-react-ui @solana/wallet-adapter-wallets @solana/wallet-adapter-base

Setup your wallet provider in your app root (e.g., _app.tsx or layout.tsx):

import { useMemo } from 'react';
import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react';
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base';
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui';
import {
  PhantomWalletAdapter,
  SolflareWalletAdapter,
  BackpackWalletAdapter,
} from '@solana/wallet-adapter-wallets';

// Import styles
import '@solana/wallet-adapter-react-ui/styles.css';

export default function App({ Component, pageProps }) {
  const network = WalletAdapterNetwork.Devnet; // or Mainnet
  const endpoint = useMemo(() => 'https://api.devnet.solana.com', []);

  const wallets = useMemo(
    () => [
      new PhantomWalletAdapter(),
      new SolflareWalletAdapter(),
      new BackpackWalletAdapter(),
    ],
    []
  );

  return (
    <ConnectionProvider endpoint={endpoint}>
      <WalletProvider wallets={wallets} autoConnect>
        <WalletModalProvider>
          <Component {...pageProps} />
        </WalletModalProvider>
      </WalletProvider>
    </ConnectionProvider>
  );
}

Use in your component:

import { createX402Client } from '@payai/x402-solana/client';
import { useWallet } from '@solana/wallet-adapter-react';
import { WalletMultiButton } from '@solana/wallet-adapter-react-ui';

function MyComponent() {
  const wallet = useWallet();

  const handlePaidRequest = async () => {
    if (!wallet.connected || !wallet.publicKey) {
      console.error('Wallet not connected');
      return;
    }

    // Create x402 client (v2)
    const client = createX402Client({
      wallet: {
        address: wallet.publicKey.toString(),
        signTransaction: async (tx) => {
          if (!wallet.signTransaction) throw new Error('Wallet does not support signing');
          return await wallet.signTransaction(tx);
        },
      },
      network: 'solana-devnet', // Simple format - automatically converted to CAIP-2
      amount: BigInt(10_000_000), // Optional: max 10 USDC safety limit
    });

    // Make a paid request - automatically handles 402 payments
    const response = await client.fetch('/api/paid-endpoint', {
      method: 'POST',
      body: JSON.stringify({ data: 'your request' }),
    });

    const result = await response.json();
    console.log('Result:', result);
  };

  return (
    <div>
      <WalletMultiButton />
      <button onClick={handlePaidRequest} disabled={!wallet.connected}>
        Make Paid Request
      </button>
    </div>
  );
}

Option 2: Using Privy

import { createX402Client } from '@payai/x402-solana/client';
import { useSolanaWallets } from '@privy-io/react-auth/solana';

function MyComponent() {
  const { wallets } = useSolanaWallets();
  const wallet = wallets[0];

  // Create x402 client (v2)
  const client = createX402Client({
    wallet,
    network: 'solana-devnet',
    amount: BigInt(10_000_000), // Optional: max 10 USDC
  });

  // Make a paid request - automatically handles 402 payments
  const response = await client.fetch('/api/paid-endpoint', {
    method: 'POST',
    body: JSON.stringify({ data: 'your request' }),
  });

  const result = await response.json();
}

Using with a Proxy Server (CORS Bypass)

If you're making requests from a browser to external APIs and encountering CORS issues, you can provide a custom fetch function that routes requests through your proxy server:

import { createX402Client } from '@payai/x402-solana/client';
import { useWallet } from '@solana/wallet-adapter-react';

function MyComponent() {
  const wallet = useWallet();

  // Create a custom fetch function that uses your proxy
  const createProxyFetch = () => {
    const proxyUrl = process.env.NEXT_PUBLIC_PROXY_URL || 'http://localhost:3001/api/proxy';

    return async (url: string | RequestInfo, init?: RequestInit): Promise<Response> => {
      // Send request through proxy server
      const response = await fetch(proxyUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          url: typeof url === 'string' ? url : url.toString(),
          method: init?.method || 'GET',
          headers: init?.headers || {},
          body: init?.body
        })
      });

      const proxyData = await response.json();

      // Reconstruct Response object with original status
      return new Response(
        typeof proxyData.data === 'string' ? proxyData.data : JSON.stringify(proxyData.data),
        {
          status: proxyData.status,
          statusText: proxyData.statusText || '',
          headers: new Headers(proxyData.headers || {})
        }
      );
    };
  };

  const handlePaidRequest = async () => {
    if (!wallet.connected || !wallet.publicKey) {
      console.error('Wallet not connected');
      return;
    }

    // Create x402 client with custom fetch (v2)
    const client = createX402Client({
      wallet: {
        address: wallet.publicKey.toString(),
        signTransaction: async (tx) => {
          if (!wallet.signTransaction) throw new Error('Wallet does not support signing');
          return await wallet.signTransaction(tx);
        },
      },
      network: 'solana-devnet',
      amount: BigInt(10_000_000),
      customFetch: createProxyFetch() // Use proxy for all requests
    });

    // All requests now go through your proxy server
    const response = await client.fetch('https://external-api.com/endpoint', {
      method: 'POST',
      body: JSON.stringify({ data: 'your request' }),
    });

    const result = await response.json();
    console.log('Result:', result);
  };

  return (
    <button onClick={handlePaidRequest} disabled={!wallet.connected}>
      Make Paid Request (via Proxy)
    </button>
  );
}

Benefits of using a proxy:

  • Bypasses browser CORS restrictions
  • Allows requests to any external x402 endpoint
  • Enables custom request/response logging
  • Provides a single point for request monitoring

Note: You need to set up your own proxy server. The customFetch parameter is optional - if not provided, the SDK uses the native fetch function.

Proxy Server Implementation

To use customFetch with a proxy, you need to implement a proxy server endpoint. Here's a complete example:

Next.js API Route (app/api/proxy/route.ts):

import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  try {
    const { url, method, headers, body } = await req.json();

    // Validate inputs
    if (!url || !method) {
      return NextResponse.json({ error: 'url and method required' }, { status: 400 });
    }

    // Prepare headers (preserve x402 v2 payment headers)
    const requestHeaders: Record<string, string> = {
      'Content-Type': headers?.['Content-Type'] || 'application/json',
      'User-Agent': 'x402-solana-proxy/2.0',
      ...(headers || {}),
    };

    // Remove problematic headers
    delete requestHeaders['host'];
    delete requestHeaders['content-length'];

    // Make request to target endpoint
    const fetchOptions: RequestInit = {
      method: method.toUpperCase(),
      headers: requestHeaders,
    };

    if (method.toUpperCase() !== 'GET' && body) {
      fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
    }

    const response = await fetch(url, fetchOptions);

    // Parse response
    const contentType = response.headers.get('content-type') || '';
    let responseData: unknown;

    if (contentType.includes('application/json')) {
      responseData = await response.json();
    } else {
      responseData = await response.text();
    }

    // Prepare response headers
    const responseHeaders: Record<string, string> = {};
    response.headers.forEach((value, key) => {
      if (
        !['content-encoding', 'transfer-encoding', 'content-length'].includes(key.toLowerCase())
      ) {
        responseHeaders[key] = value;
      }
    });

    // IMPORTANT: Return 200 with real status in body
    // This allows proper x402 402 Payment Required handling
    return NextResponse.json(
      {
        status: response.status,
        statusText: response.statusText,
        headers: responseHeaders,
        data: responseData,
        contentType,
      },
      { status: 200 }
    );
  } catch (error: unknown) {
    const message = error instanceof Error ? error.message : 'Unknown error';
    console.error('[Proxy] Error:', message);
    return NextResponse.json(
      {
        error: 'Proxy request failed',
        details: message,
      },
      { status: 500 }
    );
  }
}

Express Server (server.js):

import express from 'express';
import cors from 'cors';

const app = express();
app.use(cors());
app.use(express.json());

app.post('/api/proxy', async (req, res) => {
  try {
    const { url, method, headers, body } = req.body;

    if (!url || !method) {
      return res.status(400).json({ error: 'url and method required' });
    }

    const requestHeaders = {
      'Content-Type': headers?.['Content-Type'] || 'application/json',
      ...(headers || {}),
    };

    delete requestHeaders['host'];
    delete requestHeaders['content-length'];

    const fetchOptions = {
      method: method.toUpperCase(),
      headers: requestHeaders,
    };

    if (method.toUpperCase() !== 'GET' && body) {
      fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
    }

    const response = await fetch(url, fetchOptions);
    const contentType = response.headers.get('content-type') || '';

    let responseData;
    if (contentType.includes('application/json')) {
      responseData = await response.json();
    } else {
      responseData = await response.text();
    }

    const responseHeaders = {};
    response.headers.forEach((value, key) => {
      if (
        !['content-encoding', 'transfer-encoding', 'content-length'].includes(key.toLowerCase())
      ) {
        responseHeaders[key] = value;
      }
    });

    // Return 200 with real status in body for x402 v2 compatibility
    res.status(200).json({
      status: response.status,
      statusText: response.statusText,
      headers: responseHeaders,
      data: responseData,
      contentType,
    });
  } catch (error) {
    console.error('[Proxy] Error:', error.message);
    res.status(500).json({
      error: 'Proxy request failed',
      details: error.message,
    });
  }
});

app.listen(3001, () => console.log('Proxy server running on port 3001'));

Key Points:

  • Always return HTTP 200 from proxy, with real status code in the response body
  • This is critical for x402 v2 402 Payment Required responses to work correctly
  • Preserve x402 v2 headers (PAYMENT-SIGNATURE, PAYMENT-RESPONSE)
  • Remove problematic headers (host, content-length)

Server Side (Next.js API Route)

import { NextRequest, NextResponse } from 'next/server';
import { X402PaymentHandler } from '@payai/x402-solana/server';

const x402 = new X402PaymentHandler({
  network: 'solana-devnet', // Simple format - automatically converted to CAIP-2
  treasuryAddress: process.env.TREASURY_WALLET_ADDRESS!,
  facilitatorUrl: 'https://facilitator.payai.network',
});

export async function POST(req: NextRequest) {
  const resourceUrl = `${process.env.NEXT_PUBLIC_BASE_URL}/api/chat`;

  // 1. Extract payment header (v2 uses PAYMENT-SIGNATURE)
  const paymentHeader = x402.extractPayment(req.headers);

  // 2. Create payment requirements (v2 format)
  const paymentRequirements = await x402.createPaymentRequirements(
    {
      amount: '2500000', // $2.50 USDC (in atomic units, as string)
      asset: {
        address: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU', // USDC devnet
        decimals: 6,
      },
      description: 'AI Chat Request',
    },
    resourceUrl
  );

  if (!paymentHeader) {
    // Return 402 with v2 payment requirements
    const response = x402.create402Response(paymentRequirements, resourceUrl);
    return NextResponse.json(response.body, { status: response.status });
  }

  // 3. Verify payment
  const verified = await x402.verifyPayment(paymentHeader, paymentRequirements);
  if (!verified.isValid) {
    return NextResponse.json(
      {
        error: 'Invalid payment',
        reason: verified.invalidReason,
      },
      { status: 402 }
    );
  }

  // 4. Process your business logic
  const result = await yourBusinessLogic(req);

  // 5. Settle payment
  const settlement = await x402.settlePayment(paymentHeader, paymentRequirements);
  if (!settlement.success) {
    console.error('Settlement failed:', settlement.errorReason);
  }

  // 6. Return response
  return NextResponse.json(result);
}

Server Side (Express)

import express from 'express';
import { X402PaymentHandler } from '@payai/x402-solana/server';

const app = express();
const x402 = new X402PaymentHandler({
  network: 'solana-devnet',
  treasuryAddress: process.env.TREASURY_WALLET_ADDRESS!,
  facilitatorUrl: 'https://facilitator.payai.network',
});

app.post('/api/paid-endpoint', async (req, res) => {
  const resourceUrl = `${process.env.BASE_URL}/api/paid-endpoint`;
  const paymentHeader = x402.extractPayment(req.headers);

  const paymentRequirements = await x402.createPaymentRequirements(
    {
      amount: '2500000', // $2.50 USDC
      asset: {
        address: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU', // USDC devnet
        decimals: 6,
      },
      description: 'API Request',
    },
    resourceUrl
  );

  if (!paymentHeader) {
    const response = x402.create402Response(paymentRequirements, resourceUrl);
    return res.status(response.status).json(response.body);
  }

  const verified = await x402.verifyPayment(paymentHeader, paymentRequirements);
  if (!verified.isValid) {
    return res.status(402).json({
      error: 'Invalid payment',
      reason: verified.invalidReason,
    });
  }

  const result = await yourBusinessLogic(req);
  await x402.settlePayment(paymentHeader, paymentRequirements);

  res.json(result);
});

API Reference

Client

createX402Client(config)

Creates a new x402 client instance.

Config:

{
  wallet: WalletAdapter;              // Wallet with signTransaction method
  network: 'solana' | 'solana-devnet'; // Simple network format
  rpcUrl?: string;                    // Optional custom RPC
  amount?: bigint;                    // Optional safety limit (max payment)
  customFetch?: typeof fetch;         // Optional custom fetch for proxy support
  verbose?: boolean;                  // Optional debug logging
}

Methods:

  • client.fetch(input, init) - Make a fetch request with automatic payment handling

Server

new X402PaymentHandler(config)

Creates a new payment handler instance.

Config:

{
  network: 'solana' | 'solana-devnet'; // Simple network format
  treasuryAddress: string;            // Where payments are sent
  facilitatorUrl: string;             // Facilitator service URL
  rpcUrl?: string;                    // Optional custom RPC
  defaultToken?: TokenAsset;          // Optional default token (auto-detected)
  defaultDescription?: string;        // Optional default description
  defaultTimeoutSeconds?: number;     // Optional timeout (default: 300)
}

Methods:

  • extractPayment(headers) - Extract PAYMENT-SIGNATURE header from request
  • createPaymentRequirements(routeConfig, resourceUrl) - Create v2 payment requirements object
  • create402Response(requirements, resourceUrl) - Create v2 402 response body
  • verifyPayment(header, requirements) - Verify payment with facilitator
  • settlePayment(header, requirements) - Settle payment with facilitator
  • getNetwork() - Get the network in CAIP-2 format
  • getTreasuryAddress() - Get the treasury address

RouteConfig Format

The createPaymentRequirements method expects:

{
  amount: string;              // Payment amount in atomic units (string)
  asset: {
    address: string;           // Token mint address (USDC)
    decimals: number;          // Token decimals (6 for USDC)
  },
  description?: string;        // Optional human-readable description
  mimeType?: string;           // Optional, defaults to 'application/json'
  maxTimeoutSeconds?: number;  // Optional, defaults to 300
}

Network Configuration

CAIP-2 Network Identifiers

x402 v2 uses CAIP-2 format for network identifiers:

NetworkSimple FormatCAIP-2 Format
Mainnetsolanasolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
Devnetsolana-devnetsolana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1

The library automatically converts simple network names to CAIP-2 format internally. You can use either format in your configuration.

Network Utility Functions

import {
  toCAIP2Network,
  toSimpleNetwork,
  isSolanaNetwork,
  isSolanaMainnet,
  isSolanaDevnet,
} from '@payai/x402-solana/types';

// Convert between formats
const caip2 = toCAIP2Network('solana-devnet'); // 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1'
const simple = toSimpleNetwork('solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1'); // 'solana-devnet'

// Type guards
isSolanaNetwork('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'); // true
isSolanaMainnet('solana'); // true
isSolanaDevnet('solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1'); // true

Configuration

Environment Variables

# Network (optional, defaults to devnet)
NEXT_PUBLIC_NETWORK=solana-devnet

# Treasury wallet address (where payments are sent)
TREASURY_WALLET_ADDRESS=your_treasury_address

# Optional: Custom RPC URLs
NEXT_PUBLIC_SOLANA_RPC_DEVNET=https://api.devnet.solana.com
NEXT_PUBLIC_SOLANA_RPC_MAINNET=https://api.mainnet-beta.solana.com

# Base URL for resource field
NEXT_PUBLIC_BASE_URL=http://localhost:3000

USDC Mint Addresses

When creating payment requirements, you need to specify the USDC token mint address:

  • Devnet: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU
  • Mainnet: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

Example with environment-based selection:

const USDC_MINT =
  process.env.NODE_ENV === 'production'
    ? 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // mainnet
    : '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU'; // devnet

const paymentRequirements = await x402.createPaymentRequirements(
  {
    amount: '1000000', // $1.00 USDC
    asset: {
      address: USDC_MINT,
      decimals: 6,
    },
    description: 'Payment',
  },
  `${process.env.BASE_URL}/api/endpoint`
);

Wallet Adapter Interface

The package works with any wallet that implements this interface:

interface WalletAdapter {
  // Support for Anza wallet-adapter standard
  publicKey?: { toString(): string };
  // Alternative for custom implementations
  address?: string;
  // Required for signing
  signTransaction: (tx: VersionedTransaction) => Promise<VersionedTransaction>;
}

Compatible Wallet Providers

Solana Wallet Adapter (@solana/wallet-adapter-react)

The official Solana wallet adapter provides the most flexibility and supports multiple wallets:

import { useWallet } from '@solana/wallet-adapter-react';

const wallet = useWallet();
const walletAdapter = {
  publicKey: wallet.publicKey,
  signTransaction: wallet.signTransaction,
};

Privy (@privy-io/react-auth)

Privy wallets work out of the box:

import { useSolanaWallets } from '@privy-io/react-auth/solana';

const { wallets } = useSolanaWallets();
const wallet = wallets[0]; // Already implements the interface

Direct Wallet SDKs

You can also use wallet SDKs directly:

// Phantom
const phantomProvider = window.phantom?.solana;
const walletAdapter = {
  address: phantomProvider.publicKey.toString(),
  signTransaction: tx => phantomProvider.signTransaction(tx),
};

// Solflare
const solflareProvider = window.solflare;
const walletAdapter = {
  address: solflareProvider.publicKey.toString(),
  signTransaction: tx => solflareProvider.signTransaction(tx),
};

Payment Amounts

Payment amounts are in USDC atomic units (6 decimals) as strings:

  • 1 USDC = "1000000" atomic units
  • $0.01 = "10000" atomic units
  • $2.50 = "2500000" atomic units

Helper functions:

import { toAtomicUnits, fromAtomicUnits } from '@payai/x402-solana/utils';

const atomicUnits = toAtomicUnits(2.5, 6); // "2500000"
const usd = fromAtomicUnits('2500000', 6); // 2.5

Protocol Details

PaymentRequired Response (v2)

When a resource requires payment, the server returns a 402 status with this body:

{
  "x402Version": 2,
  "resource": {
    "url": "https://api.example.com/v1/ai/generate",
    "description": "AI text generation",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
      "amount": "2500000",
      "payTo": "2wKupLR9q6wXYppw8Gr2NvWxKBUqm4PPJKkQfoxHEBg4",
      "maxTimeoutSeconds": 300,
      "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
      "extra": {
        "feePayer": "CKPKJWNdJEqa81x7CkZ14BVPiY6y16Sxs7owznqtWYp5"
      }
    }
  ],
  "error": "Payment required"
}

PaymentPayload (v2)

The client sends payment via PAYMENT-SIGNATURE header containing base64-encoded JSON:

{
  "x402Version": 2,
  "resource": {
    "url": "https://api.example.com/v1/ai/generate",
    "description": "AI text generation",
    "mimeType": "application/json"
  },
  "accepted": {
    "scheme": "exact",
    "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
    "amount": "2500000",
    "payTo": "2wKupLR9q6wXYppw8Gr2NvWxKBUqm4PPJKkQfoxHEBg4",
    "maxTimeoutSeconds": 300,
    "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
    "extra": {
      "feePayer": "2wKupLR9q6wXYppw8Gr2NvWxKBUqm4PPJKkQfoxHDBg4"
    }
  },
  "payload": {
    "transaction": "<base64-encoded-signed-transaction>"
  }
}

Testing

Run the test suite:

npm test

The tests verify:

✅ Package imports work correctly
✅ Client can be created with wallet adapter
✅ Automatic 402 payment handling works
✅ Transaction signing and submission succeed
✅ Payment verification and settlement complete

Architecture

src/
├── client/                    # Client-side code
│   ├── transaction-builder.ts # Solana transaction construction
│   ├── payment-interceptor.ts # 402 payment fetch interceptor
│   └── index.ts              # Main client export
├── server/                    # Server-side code
│   ├── facilitator-client.ts # Facilitator API communication
│   ├── payment-handler.ts    # Payment verification & settlement
│   └── index.ts              # Main server export
├── types/                     # TypeScript types
│   ├── x402-protocol.ts      # x402 v2 spec types (CAIP-2 networks)
│   ├── solana-payment.ts     # Solana-specific types
│   └── index.ts
├── utils/                     # Utilities
│   ├── helpers.ts            # Helper functions
│   └── index.ts
└── index.ts                   # Main package export

Development

Running Tests

npm test

Linting

npm run lint
npm run lint:fix  # Auto-fix issues

Type Checking

npm run typecheck

Building

npm run build

Future Enhancements

  • Add @solana/kit adapter for AI agents
  • Support for multiple payment tokens
  • Add transaction retry logic
  • Support for partial payments
  • Extensions support (SIWx, Discovery)

License

MIT

Credits

Built on top of:

Support

Version

Current version: 2.0.0 (x402 Protocol v2)

Keywords

x402

FAQs

Package last updated on 05 Jan 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts