Skip to main content
This example demonstrates a minimal integration using x402 v2 with axios. Despite the name “fetch”, this example uses the @x402/axios package for consistency and simplicity. Perfect for Node.js applications with minimal setup.

Overview

@x402/axios v2 provides a minimal integration with automatic x402 payment handling, with support for both EVM and SVM networks.

Features

  • Base (EVM) and Solana (SVM) network support
  • Minimal setup - Quick integration
  • Minimal dependencies
  • Type-safe TypeScript
  • Simple pattern

Prerequisites

  • Node.js 18+
  • USDC balance on Base or Solana
  • EVM private key (for Base) or SVM private key (for Solana)

Installation

npm install axios @x402/axios @x402/evm @x402/svm viem bs58

Quick Start

1. Set Up Environment

Create a .env file:
# For Base network
EVM_PRIVATE_KEY=0x...
# For Solana network
SVM_PRIVATE_KEY=base58_key...
# Common
RECEIVER=your_x_username
AMOUNT=0.01

2. Implement Base (EVM) Payment

Create base-send.ts:
import axios from "axios";
import { privateKeyToAccount } from "viem/accounts";
import {
  x402Client,
  wrapAxiosWithPayment,
  decodePaymentResponseHeader,
} from "@x402/axios";
import { registerExactEvmScheme } from "@x402/evm/exact/client";

const evmPrivateKey = process.env.EVM_PRIVATE_KEY as `0x${string}`;
const receiver = process.env.RECEIVER as string;
const amount = parseFloat(process.env.AMOUNT || "0.01");

async function sendPayment() {
  console.log("🚀 Starting Snack Money payment with x402 v2\n");
  console.log("ℹ️  Network: Base (EVM)\n");

  // Create Base signer
  const evmAccount = privateKeyToAccount(evmPrivateKey);
  console.log("✅ Base signer created:", evmAccount.address);

  // Create x402 client and register EVM scheme
  const client = new x402Client();
  registerExactEvmScheme(client, { signer: evmAccount });
  console.log("✅ Registered EVM payment scheme\n");

  // Wrap axios with payment interceptor
  const api = wrapAxiosWithPayment(
    axios.create({ baseURL: "https://api.snack.money" }),
    client
  );

  console.log(`💸 Sending ${amount} USDC to @${receiver} on X via Base...\n`);

  try {
    const response = await api.post("/payments/x/pay", {
      amount,
      currency: "USDC",
      receiver,
      description: "Payment via x402 v2 (Base)"
    });

    console.log("✅ Payment successful!");
    console.log("\n📊 Response:", JSON.stringify(response.data, null, 2));

    const paymentResponseHeader = response.headers["payment-response"];
    if (paymentResponseHeader) {
      const paymentResponse = decodePaymentResponseHeader(paymentResponseHeader);
      console.log("\n🔐 Payment Response Details:", JSON.stringify(paymentResponse, null, 2));
    }
  } catch (error) {
    console.error("❌ Payment failed:", error);
    throw error;
  }
}

sendPayment();

3. Implement Solana (SVM) Payment

Create solana-send.ts:
import axios from "axios";
import {
  x402Client,
  wrapAxiosWithPayment,
  decodePaymentResponseHeader,
} from "@x402/axios";
import { registerExactSvmScheme } from "@x402/svm/exact/client";
import { createKeyPairSignerFromBytes } from "@solana/kit";
import bs58 from "bs58";

const svmPrivateKey = process.env.SVM_PRIVATE_KEY as string;
const receiver = process.env.RECEIVER as string;
const amount = parseFloat(process.env.AMOUNT || "0.01");

async function sendPayment() {
  console.log("🚀 Starting Snack Money payment with x402 v2\n");
  console.log("ℹ️  Network: Solana (SVM)\n");

  // Create Solana signer
  const privateKeyBytes = bs58.decode(svmPrivateKey);
  const solanaSigner = await createKeyPairSignerFromBytes(privateKeyBytes);
  console.log("✅ Solana signer created:", solanaSigner.address);

  // Create x402 client and register Solana scheme
  const client = new x402Client();
  registerExactSvmScheme(client, { signer: solanaSigner });
  console.log("✅ Registered Solana payment scheme\n");

  // Wrap axios with payment interceptor
  const api = wrapAxiosWithPayment(
    axios.create({ baseURL: "https://api.snack.money" }),
    client
  );

  console.log(`💸 Sending ${amount} USDC to @${receiver} on X via Solana...\n`);

  try {
    const response = await api.post("/payments/x/pay", {
      amount,
      currency: "USDC",
      receiver,
      description: "Payment via x402 v2 (Solana)"
    });

    console.log("✅ Payment successful!");
    console.log("\n📊 Response:", JSON.stringify(response.data, null, 2));

    const paymentResponseHeader = response.headers["payment-response"];
    if (paymentResponseHeader) {
      const paymentResponse = decodePaymentResponseHeader(paymentResponseHeader);
      console.log("\n🔐 Payment Response Details:", JSON.stringify(paymentResponse, null, 2));
    }
  } catch (error) {
    console.error("❌ Payment failed:", error);
    throw error;
  }
}

sendPayment();

4. Run the Example

For Base network:
npm run base
# or
npx tsx base-send.ts
For Solana network:
npm run solana
# or
npx tsx solana-send.ts

Expected Output

🚀 Starting Snack Money payment with x402-fetch (BASE)

✅ Created Base signer
💸 Sending 0.01 USDC to @username on X...

✅ Payment successful!

📊 Response: {
  "code": 200,
  "msg": "0.01 USDC sent successfully",
  "data": {
    "txn_id": "0xabc...def",
    "amount": 0.01,
    "receipt": "https://snack.money/x/username?txn=..."
  }
}

Network Support

Base (EVM)

import { privateKeyToAccount } from "viem/accounts";

const signer = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const client = withPayment(fetch, signer);

Solana (SVM)

import { Keypair } from "@solana/web3.js";
import bs58 from "bs58";

const keypair = Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY));
const client = withPayment(fetch, keypair);

Switching Networks

Simply change the NETWORK environment variable:
# Use Base
NETWORK=base PRIVATE_KEY=0x... npm run dev

# Use Solana
NETWORK=solana PRIVATE_KEY=... npm run dev

Supported Platforms

// X (Twitter)
await client("https://api.snack.money/payments/x/pay", {
  method: "POST",
  body: JSON.stringify({ amount: 0.01, receiver: "username", currency: "USDC" })
});

// Farcaster
await client("https://api.snack.money/payments/farcaster/pay", {
  method: "POST",
  body: JSON.stringify({ amount: 0.5, receiver: "username", currency: "USDC" })
});

// GitHub
await client("https://api.snack.money/payments/github/pay", {
  method: "POST",
  body: JSON.stringify({ amount: 1.0, receiver: "username", currency: "USDC" })
});

Error Handling

try {
  const response = await client("https://api.snack.money/payments/x/pay", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ amount: 0.01, receiver: "username", currency: "USDC" })
  });

  if (!response.ok) {
    const error = await response.json();
    console.error("Payment failed:", error);
    return;
  }

  const data = await response.json();
  console.log("Success:", data);
} catch (error) {
  console.error("Network error:", error);
}

Why x402-fetch?

Advantages

  • Minimal Dependencies: Uses native fetch
  • Multi-Chain: Supports Base and Solana
  • Lightweight: Small bundle size
  • Familiar API: Standard fetch interface

Best For

  • Node.js applications
  • Minimal dependency requirements
  • Multi-chain support needed
  • Backend services

Full Example Repository

View on GitHub → Includes:
  • Base and Solana implementations
  • Environment templates
  • Complete setup guide

Next Steps

Dependencies

{
  "dependencies": {
    "axios": "^1.7.9",
    "@x402/axios": "^2.0.0",
    "@x402/evm": "^2.0.0",
    "@x402/svm": "^2.0.0",
    "viem": "^2.39.3",
    "bs58": "^6.0.0",
    "dotenv": "^16.4.7"
  },
  "devDependencies": {
    "@types/node": "^20.0.0",
    "typescript": "^5.0.0"
  }
}

Learn More