JSPM

  • Created
  • Published
  • Downloads 355
  • Score
    100M100P100Q101291F
  • License MIT

Chain-agnostic x402 v2 SDK for Solana, Base, and EVM payments

Package Exports

  • @dexterai/x402/adapters
  • @dexterai/x402/client
  • @dexterai/x402/react
  • @dexterai/x402/server
  • @dexterai/x402/utils

Readme

Dexter

@dexterai/x402

The x402 SDK that actually works.

npm Node Live Demo

๐Ÿ‘‰ Try it with real payments โ†’


โœจ Why This SDK?

  • ๐Ÿ”— Multi-chain โ€” Solana and Base, same API
  • โšก x402 v2 โ€” Full protocol support, verified working
  • โš›๏ธ React Hook โ€” useX402Payment with loading states, balances, and transaction tracking
  • ๐Ÿ’ฐ Smart Balance Check โ€” Clear "insufficient funds" error before the wallet popup
  • ๐Ÿ‘ป Phantom Compatible โ€” Handles Lighthouse safety assertions automatically
  • ๐Ÿ“ฆ Zero Config โ€” Wrap fetch(), payments just work

๐ŸŽฎ See It Working

Don't take our word for it. Make a real payment yourself:

โ†’ dexter.cash/sdk

The demo uses this exact SDK. Solana and Base. Real USDC. Real transactions.


๐Ÿš€ Quick Start

Install

npm install @dexterai/x402

Client (Browser)

import { createX402Client } from '@dexterai/x402/client';

const client = createX402Client({
  wallets: {
    solana: solanaWallet,
    evm: evmWallet,
  },
  rpcUrls: {
    'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': 'https://your-solana-rpc.com',
    'eip155:8453': 'https://your-base-rpc.com',
  },
});

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

React

import { useX402Payment } from '@dexterai/x402/react';

function PayButton() {
  const { fetch, isLoading, balances, transactionUrl } = useX402Payment({
    wallets: { solana: solanaWallet, evm: evmWallet },
    rpcUrls: { /* your RPC endpoints */ },
  });

  return (
    <div>
      <p>Balance: ${balances[0]?.balance.toFixed(2)}</p>
      <button onClick={() => fetch(url)} disabled={isLoading}>
        {isLoading ? 'Paying...' : 'Pay'}
      </button>
      {transactionUrl && <a href={transactionUrl}>View Transaction โ†—</a>}
    </div>
  );
}

๐ŸŒ Supported Networks

Network Identifier Status
Solana Mainnet solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp โœ… Verified
Base Mainnet eip155:8453 โœ… Verified

All networks use USDC.


๐Ÿ“ฆ Package Exports

// Client - browser & Node.js
import { createX402Client } from '@dexterai/x402/client';

// React hook
import { useX402Payment } from '@dexterai/x402/react';

// Server helpers (see note below)
import { createX402Server } from '@dexterai/x402/server';

// Chain adapters (advanced)
import { createSolanaAdapter, createEvmAdapter } from '@dexterai/x402/adapters';

// Utilities
import { toAtomicUnits, fromAtomicUnits } from '@dexterai/x402/utils';

๐Ÿ› ๏ธ Utilities

import { toAtomicUnits, fromAtomicUnits } from '@dexterai/x402/utils';

// Convert dollars to atomic units (for API calls)
toAtomicUnits(0.05, 6);  // '50000'
toAtomicUnits(1.50, 6);  // '1500000'

// Convert atomic units back to dollars (for display)
fromAtomicUnits('50000', 6);   // 0.05
fromAtomicUnits(1500000n, 6);  // 1.5

๐Ÿ–ฅ๏ธ Server SDK

import { createX402Server } from '@dexterai/x402/server';

const server = createX402Server({
  payTo: 'YourAddress...',
  network: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
  facilitatorUrl: 'https://x402.dexter.cash',
});

// In your route handler
app.post('/protected', async (req, res) => {
  const paymentSig = req.headers['payment-signature'];

  if (!paymentSig) {
    const requirements = await server.buildRequirements({
      amountAtomic: '50000',  // $0.05 USDC
      resourceUrl: req.originalUrl,
    });
    res.setHeader('PAYMENT-REQUIRED', server.encodeRequirements(requirements));
    return res.status(402).json({});
  }

  const result = await server.settlePayment(paymentSig);
  if (!result.success) {
    return res.status(402).json({ error: result.errorReason });
  }

  res.json({ data: 'Your protected content' });
});

โš ๏ธ Note: The server SDK has not been battle-tested in production yet. The client SDK and React hook have been verified with real payments at dexter.cash/sdk.


๐Ÿ’ธ Dynamic Pricing

For LLM/AI endpoints where cost scales with input size:

import { createX402Server, createDynamicPricing } from '@dexterai/x402/server';

const server = createX402Server({ payTo: '...', network: '...' });
const pricing = createDynamicPricing({
  unitSize: 1000,      // chars per unit
  ratePerUnit: 0.01,   // $0.01 per unit
  minUsd: 0.01,        // floor
  maxUsd: 10.00,       // ceiling
});

app.post('/api/llm', async (req, res) => {
  const { prompt } = req.body;
  const paymentSig = req.headers['payment-signature'];

  if (!paymentSig) {
    const quote = pricing.calculate(prompt);
    const requirements = await server.buildRequirements({
      amountAtomic: quote.amountAtomic,
      resourceUrl: req.originalUrl,
    });
    res.setHeader('PAYMENT-REQUIRED', server.encodeRequirements(requirements));
    res.setHeader('X-Quote-Hash', quote.quoteHash);
    return res.status(402).json({ usdAmount: quote.usdAmount });
  }

  // Validate quote hasn't changed (prevents prompt manipulation)
  const quoteHash = req.headers['x-quote-hash'];
  if (!pricing.validateQuote(prompt, quoteHash)) {
    return res.status(400).json({ error: 'Prompt changed, re-quote required' });
  }

  const result = await server.settlePayment(paymentSig);
  if (!result.success) return res.status(402).json({ error: result.errorReason });

  const response = await runLLM(prompt);
  res.json(response);
});

The client SDK automatically forwards X-Quote-Hash on retry.


๐Ÿ“‹ API Reference

createX402Client(options)

Option Type Description
wallet SolanaWallet Single Solana wallet (legacy)
wallets { solana?, evm? } Multi-chain wallets
preferredNetwork string Prefer this network when multiple options available
rpcUrls Record<string, string> RPC endpoints per network (CAIP-2 format)
maxAmountAtomic string Maximum payment cap
verbose boolean Enable debug logging

useX402Payment(options)

Returns:

Property Type Description
fetch function Payment-aware fetch
isLoading boolean Payment in progress
status string 'idle' | 'pending' | 'success' | 'error'
error X402Error? Error details if failed
transactionId string? Transaction signature
transactionUrl string? Block explorer link
balances Balance[] Token balances per chain
refreshBalances function Manual refresh
reset function Clear state

๐Ÿ”ง Development

npm run build      # Build ESM + CJS
npm run dev        # Watch mode
npm run typecheck  # TypeScript
npm test           # Run tests

๐Ÿ“„ License

MIT โ€” see LICENSE


Dexter Facilitator ยท Live Demo ยท Become a Seller