SDK Reference

Complete API reference for @zan_team/x402

Installation

npm install @zan_team/x402 viem

Solana optional dependencies (only needed for SVM auth/payment):

npm install @solana/web3.js @solana/spl-token bs58 tweetnacl

Requires Node.js >= 18.

Client creation

import { createX402Client } from '@zan_team/x402';

// EVM wallet
const client = await createX402Client({
  gatewayUrl: 'https://x402.zan.top',
  privateKey: process.env.PRIVATE_KEY as `0x${string}`,
  autoPayment: true,
  preAuth: true,
});

// Solana wallet
const svmClient = await createX402Client({
  gatewayUrl: 'https://x402.zan.top',
  svmPrivateKey: process.env.SOLANA_KEY, // Base58
  chainType: 'SVM',
  autoPayment: true,
  preAuth: true,
});

Configuration

interface X402ClientConfig {
  gatewayUrl: string;
  // EVM
  wallet?: WalletClient;
  privateKey?: `0x${string}`;
  // SVM
  svmPrivateKey?: string;       // Base58
  paymentNetwork?: string;      // CAIP-2, e.g. "eip155:8453"
  solanaRpcUrl?: string;
  // Behavior
  chainType?: 'EVM' | 'SVM';   // auto-detected from keys
  autoPayment?: boolean;        // default: false
  defaultBundle?: BundleType;   // default: 'default'
  preAuth?: boolean;            // pre-authenticate on creation
  timeout?: number;             // ms, default: 30000
  aiTimeout?: number;           // ms, default: 120000 (AI calls)
  fetch?: typeof fetch;         // custom fetch implementation
}
ParameterTypeDefaultDescription
gatewayUrlstringGateway URL (required)
privateKey0x${string}EVM private key
svmPrivateKeystringSolana private key (Base58)
chainType'EVM' | 'SVM'auto-detectWallet type
autoPaymentbooleanfalseAutomatically handle 402 payments
preAuthbooleanfalseAuthenticate on client creation
defaultBundlestring'default'Bundle used for auto-purchase
paymentNetworkstringPayment network (CAIP-2 format)
timeoutnumber30000General request timeout (ms)
aiTimeoutnumber120000AI call timeout (ms)
solanaRpcUrlstringSolana RPC for building transactions

Architecture

X402Client
├── auth       AuthModule       SIWE/SIWS + JWT lifecycle
├── credits    CreditsModule    balance · purchase · usage · payment status
├── rpc        RpcModule        JSON-RPC · batch · generic provider forward
├── ai         AiModule         AI model chat · rolling settlement · history · stats
└── discovery  DiscoveryModule  health · providers · networks · bundles · AI models

Subpath exports for tree-shaking: @zan_team/x402/auth, @zan_team/x402/credits, @zan_team/x402/rpc, @zan_team/x402/ai.

Core API

createX402Client(config): Promise<X402Client>

Creates and initializes the client. If preAuth: true, performs SIWE/SIWS authentication before returning.

const client = await createX402Client({ gatewayUrl, privateKey, autoPayment: true, preAuth: true });

client.call(ecosystem, network, method, params?): Promise<JsonRpcResponse>

Calls a JSON-RPC method on the specified chain. Credits are deducted per method weight.

const block = await client.call('eth', 'mainnet', 'eth_blockNumber');
const balance = await client.call('eth', 'mainnet', 'eth_getBalance', ['0x...', 'latest']);
const slot = await client.call('solana', 'mainnet', 'getSlot');

With autoPayment: true, automatically purchases credits if balance is insufficient.

client.chat(model, options): Promise<AiResponse>

Calls an AI model. Uses rolling settlement: first call is free, subsequent calls settle the previous call's token cost.

const response = await client.chat('deepseek-v4-flash', {
  messages: [{ role: 'user', content: 'Hello' }],
  max_tokens: 1024,
});

console.log(response.data.content);       // AI response text
console.log(response.data.model);         // model used
console.log(response.data.usage);         // { prompt_tokens, completion_tokens, total_tokens }
console.log(response.data.finish_reason); // "stop"
console.log(response.txHash);            // payment tx hash (null on first call)
console.log(response.paymentNetwork);    // "eip155:8453" (null on first call)

With autoPayment: true, automatically signs payment for previous call's token cost.

client.getBalance(): Promise<BalanceResponse>

Returns current credit balance and usage statistics.

const bal = await client.getBalance();
console.log(bal.balance);         // current credits
console.log(bal.totalPurchased);  // lifetime purchased
console.log(bal.totalConsumed);   // lifetime consumed
console.log(bal.wallet);          // wallet address
console.log(bal.tier);            // "trial" | "standard"

client.purchaseCredits(bundle): Promise<PurchaseReceipt>

Explicitly purchases a credit bundle via x402 payment.

const receipt = await client.purchaseCredits('default');
console.log(receipt.creditsPurchased); // 100000
console.log(receipt.balance);          // new balance
console.log(receipt.txHash);           // on-chain tx hash
console.log(receipt.paymentNetwork);   // "eip155:8453"

client.listBundles(): Promise<BundlesResponse>

Lists available credit bundles and their pricing.

const { bundles } = await client.listBundles();
// [{ name: 'default', credits: 100000, price: '0.015', description: '~5,000 RPC calls' }]

client.fetch(path, options): Promise<Response>

Low-level HTTP method with automatic JWT injection. Use for custom endpoints.

const response = await client.fetch('/credits/usage?limit=50', { method: 'GET' });

Discovery API

All discovery methods are available without authentication.

client.discovery.health(): Promise<HealthResponse>

const health = await client.discovery.health();
// { status: "ok", uptime: 3600 }

client.discovery.listProviders(): Promise<ProvidersResponse>

const { providers } = await client.discovery.listProviders();
// [{ id: "zan-rpc", name: "ZAN Multi-chain RPC", type: "PROXY", routes: [...] }]

client.discovery.listNetworks(): Promise<NetworksResponse>

const { networks } = await client.discovery.listNetworks();
// [{ ecosystem: "eth", network: "mainnet", providerId: "zan-rpc" }, ...]

client.discovery.listBundles(): Promise<BundlesResponse>

const { bundles } = await client.discovery.listBundles();

client.discovery.listAiModels(): Promise<AiModelsResponse>

const { models } = await client.discovery.listAiModels();
models.forEach(m => {
  console.log(`${m.id}: input=${m.inputPricePerToken}, output=${m.outputPricePerToken}`);
});

Error hierarchy

All errors extend X402Error with typed code and optional statusCode.

import { X402Error, AuthenticationError, InsufficientCreditsError } from '@zan_team/x402';

try {
  await client.call('eth', 'mainnet', 'eth_blockNumber');
} catch (err) {
  if (err instanceof InsufficientCreditsError) {
    console.log(`Need ${err.required} credits, have ${err.balance}`);
  } else if (err instanceof X402Error) {
    console.log(`x402 error: ${err.code} (HTTP ${err.statusCode})`);
  }
}
ErrorHTTPScenarioSDK behavior with autoPayment: true
AuthenticationError401SIWE/SIWS signature rejectedThrows (cannot auto-fix)
SessionExpiredError401JWT expiredAuto re-authenticates and retries
InsufficientCreditsError402Not enough creditsAuto purchases credits and retries
InsufficientFundsError402On-chain USDC too lowThrows (cannot auto-fix)
PaymentRejectedError402Facilitator rejected paymentThrows
MethodNotAllowedError403Method blocked by gatewayThrows (cannot retry)
ProviderNotFoundError404No matching routeThrows
AiModelNotFoundError404AI model not supportedThrows
AiPaymentRequiredError402AI payment neededAuto signs and retries
AiUpstreamError502/504AI upstream failureThrows (not charged)
UpstreamError504Provider failureThrows (credits refunded)
NetworkErrorTransport / timeoutThrows

Auto-payment flows

RPC (credit-based)

client.call()
    │
    ▼
POST /rpc/{eco}/{net} → 402 insufficient_credits
    │
    ▼ [autoPayment: true]
POST /credits/purchase/default → 402 + PAYMENT-REQUIRED
    │
    ▼ [SDK signs EIP-3009 or Solana SPL]
POST /credits/purchase/default + PAYMENT-SIGNATURE → 200
    │
    ▼ [credits topped up]
POST /rpc/{eco}/{net} (retry) → 200 + result

AI (rolling settlement)

client.chat() [first call]
    │
    ▼
POST /ai/{model} → 200 + response (free, usage recorded as pending)

client.chat() [subsequent call]
    │
    ▼
POST /ai/{model} → 402 (settle previous token cost)
    │
    ▼ [autoPayment: true, SDK signs payment]
POST /ai/{model} + PAYMENT-SIGNATURE → 200 + response + txHash

Advanced patterns

Custom payment network

const client = await createX402Client({
  gatewayUrl: 'https://x402.zan.top',
  privateKey: '0x...',
  autoPayment: true,
  paymentNetwork: 'eip155:8453', // Base Mainnet
});

Solana client

const client = await createX402Client({
  gatewayUrl: 'https://x402.zan.top',
  svmPrivateKey: '<Base58 secret key>',
  chainType: 'SVM',
  paymentNetwork: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // Mainnet
  solanaRpcUrl: 'https://api.mainnet-beta.solana.com',
  autoPayment: true,
  preAuth: true,
});

Manual payment control

const client = await createX402Client({
  gatewayUrl: 'https://x402.zan.top',
  privateKey: '0x...',
  autoPayment: false, // handle payments yourself
  preAuth: true,
});

// Check balance before calling
const { balance } = await client.getBalance();
if (balance < 100) {
  await client.purchaseCredits('default');
}

// Now call (will throw InsufficientCreditsError if still not enough)
const block = await client.call('eth', 'mainnet', 'eth_blockNumber');

Error handling pattern

import {
  InsufficientFundsError,
  AiUpstreamError,
  NetworkError,
} from '@zan_team/x402';

async function reliableCall(client, model, messages) {
  try {
    return await client.chat(model, { messages, max_tokens: 1024 });
  } catch (err) {
    if (err instanceof InsufficientFundsError) {
      // Wallet needs more USDC — alert user
      console.error('Wallet USDC balance too low for payment');
      throw err;
    }
    if (err instanceof AiUpstreamError) {
      // Upstream model failed — not charged, safe to retry with different model
      return await client.chat('deepseek-v4-flash', { messages, max_tokens: 1024 });
    }
    if (err instanceof NetworkError) {
      // Transient network issue — retry after delay
      await new Promise(r => setTimeout(r, 2000));
      return await client.chat(model, { messages, max_tokens: 1024 });
    }
    throw err;
  }
}

Next steps



Did this page help you?