Skip to main content

What is Exact Payment?

The “exact payment” approach uses @faremeter/payment-solana/exact to give you complete control over the x402 payment flow on Solana. Unlike @faremeter/rides, which abstracts away the details, this approach lets you:
  • Manually create and configure wallets
  • Control network connections and RPC endpoints
  • Choose specific payment tokens and mints
  • Integrate custom wallet adapters (Ledger, Crossmint, Squads)
  • Access the low-level x402 protocol

When to Use This Approach

Use exact payment when you need:
  • Custom wallet implementations
  • Fine-grained control over payment configuration
  • Integration with existing Solana infrastructure
  • Multiple payment tokens or networks
Use @faremeter/rides when:
  • You want the simplest possible integration (3 lines of code)
  • You’re prototyping or building a quick demo
  • You don’t need custom wallet logic
  • Default payment configuration is sufficient

Full Example

This example shows how to make an x402-paid API call to Helius using the exact payment approach:
import {
  clusterApiUrl,
  Connection,
  Keypair,
  PublicKey,
} from "@solana/web3.js";
import { createLocalWallet } from "@faremeter/wallet-solana";
import { lookupKnownSPLToken } from "@faremeter/info/solana";
import { createPaymentHandler } from "@faremeter/payment-solana/exact";
import { wrap as wrapFetch } from "@faremeter/fetch";

async function main() {
  // Load your private key from environment
  const { PAYER_KEYPAIR } = process.env;
  if (!PAYER_KEYPAIR) {
    throw new Error("PAYER_KEYPAIR environment variable must be set");
  }

  const keypair = Keypair.fromSecretKey(
    Uint8Array.from(JSON.parse(PAYER_KEYPAIR))
  );

  // Configure network
  const network = "mainnet-beta"; // or "devnet", "testnet"

  // Lookup the USDC token mint address for this network
  const usdcInfo = lookupKnownSPLToken(network, "USDC");
  if (!usdcInfo) {
    throw new Error("Could not find USDC mint for network");
  }
  const mint = new PublicKey(usdcInfo.address);
  // mainnet USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

  // Create Solana connection (configure your own RPC endpoint if needed)
  const connection = new Connection(
    clusterApiUrl(network),
    "confirmed" // commitment level
  );

  // Create a wallet interface from your keypair
  const wallet = await createLocalWallet(network, keypair);

  // Create the payment handler
  const paymentHandler = createPaymentHandler(wallet, mint, connection);

  // Wrap fetch with the payment handler
  const fetchWithPayer = wrapFetch(fetch, {
    handlers: [paymentHandler],
  });

  // Make an x402-paid API call
  const url = "https://helius.api.corbits.dev";
  const payload = {
    jsonrpc: "2.0",
    id: 1,
    method: "getBlockHeight",
  };

  const response = await fetchWithPayer(url, {
    method: "POST",
    headers: {
      "Accept": "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    const text = await response.text().catch(() => "");
    throw new Error(`HTTP ${response.status}: ${text}`);
  }

  const data = await response.json();
  console.log("Block Height:", data.result);
  console.log("Payment successful - 0.01 USDC charged");
}

main().catch(console.error);

Step-by-Step Breakdown

1. Token Lookup

const usdcInfo = lookupKnownSPLToken(network, "USDC");
const mint = new PublicKey(usdcInfo.address);
The lookupKnownSPLToken() function finds the correct USDC mint address for your network:
  • mainnet-beta: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
  • devnet: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU
This prevents hardcoding mint addresses and ensures you’re using the right token.

2. Wallet Creation

const wallet = await createLocalWallet(network, keypair);
This creates a wallet interface that:
  • Signs transactions using your private key
  • Implements the x402 wallet protocol
  • Can be swapped with other wallet adapters (Ledger, Crossmint, Squads)
Alternative wallet types:
// Ledger hardware wallet
import { createLedgerSolanaWallet } from "@faremeter/wallet-ledger";
const wallet = await createLedgerSolanaWallet(network, "44'/501'/0'/0'");

// Crossmint custodial wallet
import { createCrossmintWallet } from "@faremeter/wallet-crossmint";
const wallet = await createCrossmintWallet(network, crossmintApiKey, crossmintWalletAddress);

// Squads multisig
import { createSquadsWallet } from "@faremeter/wallet-solana-squads";
const wallet = await createSquadsWallet(network, connection, keypair, multisigPda, squadMember);

3. Payment Handler

const paymentHandler = createPaymentHandler(wallet, mint, connection);
The payment handler:
  • Intercepts HTTP 402 (Payment Required) responses
  • Reads the payment amount from the response
  • Creates and signs a Solana SPL token transfer
  • Submits the transaction to the network
  • Retries the original request with payment proof

4. Fetch Wrapping

const fetchWithPayer = wrapFetch(fetch, {
  handlers: [paymentHandler],
});
This wraps the native fetch() function to automatically handle x402 payments. You can add multiple handlers for different payment methods or networks.

Comparison: Exact vs Rides

import {
  clusterApiUrl,
  Connection,
  Keypair,
  PublicKey,
} from "@solana/web3.js";
import { createLocalWallet } from "@faremeter/wallet-solana";
import { lookupKnownSPLToken } from "@faremeter/info/solana";
import { createPaymentHandler } from "@faremeter/payment-solana/exact";
import { wrap as wrapFetch } from "@faremeter/fetch";

const { PAYER_KEYPAIR } = process.env;
const keypair = Keypair.fromSecretKey(
  Uint8Array.from(JSON.parse(PAYER_KEYPAIR))
);

const network = "mainnet-beta";
const usdcInfo = lookupKnownSPLToken(network, "USDC");
const mint = new PublicKey(usdcInfo.address);
const connection = new Connection(clusterApiUrl(network));

const wallet = await createLocalWallet(network, keypair);
const fetchWithPayer = wrapFetch(fetch, {
  handlers: [createPaymentHandler(wallet, mint, connection)],
});

// Make API call
const response = await fetchWithPayer(url, options);
Tradeoffs:
  • Exact: 40+ lines, full control, custom wallets
  • Rides: 3 lines, fast setup, limited customization, great for demos