Clients 6 min read

Making Payments

Learn how to build x402 clients that can pay for services

x402 clients automatically handle the payment flow:

  1. Make a request to a protected endpoint
  2. Receive 402 Payment Required with payment details
  3. Create and sign a payment transaction
  4. Retry the request with payment proof
  5. Receive the requested resource

Rust (x402-reqwest)

The x402-reqwest crate provides a drop-in replacement for reqwest that handles x402 payments automatically.

Installation

[dependencies]
x402-reqwest = "0.6"
x402-rs = "0.10"
reqwest = "0.12"
tokio = { version = "1", features = ["full"] }
alloy = { version = "0.15", features = ["signers"] }
dotenvy = "0.15"

EVM Payments (Base, Ethereum, etc.)

use alloy::signers::local::PrivateKeySigner;
use dotenvy::dotenv;
use reqwest::Client;
use std::env;
use x402_reqwest::chains::evm::EvmSenderWallet;
use x402_reqwest::{MaxTokenAmountFromAmount, ReqwestWithPayments, ReqwestWithPaymentsBuild};
use x402_rs::network::{Network, USDCDeployment};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    dotenv().ok();
    
    // Load your wallet from environment (never hardcode real keys!)
    let signer: PrivateKeySigner = env::var("EVM_PRIVATE_KEY")?.parse()?;
    let sender = EvmSenderWallet::new(signer);

    // Create x402-enabled client with vanilla reqwest
    let http_client = Client::new()
        .with_payments(sender)
        .prefer(USDCDeployment::by_network(Network::BaseSepolia))
        .max(USDCDeployment::by_network(Network::BaseSepolia).amount(0.1)?)
        .build();

    // Make request - payment handled automatically
    let response = http_client
        .get("http://localhost:3000/protected-route")
        .send()
        .await?;

    println!("Response: {:?}", response.text().await?);

    Ok(())
}

Solana Payments

use dotenvy::dotenv;
use reqwest::Client;
use solana_sdk::signature::Keypair;
use std::env;
use x402_reqwest::chains::solana::SolanaSenderWallet;
use x402_reqwest::{MaxTokenAmountFromAmount, ReqwestWithPayments, ReqwestWithPaymentsBuild};
use x402_rs::network::{Network, USDCDeployment};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    dotenv().ok();
    
    // Load Solana wallet
    let solana_private_key = env::var("SOLANA_PRIVATE_KEY")?;
    let keypair = Keypair::from_base58_string(solana_private_key.as_str());
    let solana_rpc_url = env::var("SOLANA_RPC_URL")?;
    let rpc_client = solana_client::rpc_client::RpcClient::new(solana_rpc_url.as_str());
    let sender = SolanaSenderWallet::new(keypair, rpc_client);

    // Create x402-enabled client
    let http_client = Client::new()
        .with_payments(sender)
        .prefer(USDCDeployment::by_network(Network::Solana))
        .max(USDCDeployment::by_network(Network::Solana).amount(0.1)?)
        .build();

    // Make request - payment handled automatically
    let response = http_client
        .get("http://localhost:3000/protected-route")
        .send()
        .await?;

    println!("Response: {:?}", response.text().await?);

    Ok(())
}

Configuration Options

// Create client with payment configuration
let http_client = Client::new()
    .with_payments(sender)
    
    // Preferred token/network for payments
    .prefer(USDCDeployment::by_network(Network::BaseSepolia))
    
    // Maximum payment amount per request (in token units)
    .max(USDCDeployment::by_network(Network::BaseSepolia).amount(0.1)?)
    
    .build();

TypeScript / JavaScript

For TypeScript clients, you can use x402-fetch or x402-axios to automatically handle 402 Payment Required responses.

Installation

# Using fetch
npm install x402-fetch viem

# Or using Axios
npm install x402-axios axios viem

Create a Wallet Client

import { privateKeyToAccount } from "viem/accounts";

// Create a wallet account (use environment variable for the key!)
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

Using x402-fetch

x402-fetch extends the native fetch API to handle 402 responses and payment headers automatically.

import { wrapFetchWithPayment, decodeXPaymentResponse } from "x402-fetch";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

// Wrap fetch with payment handling
const fetchWithPayment = wrapFetchWithPayment(fetch, account);

// Make request - payment handled automatically
fetchWithPayment("https://api.example.com/paid-endpoint", {
  method: "GET",
})
  .then(async response => {
    const body = await response.json();
    console.log(body);

    // Optionally decode the payment response
    const paymentResponse = decodeXPaymentResponse(
      response.headers.get("x-payment-response")!
    );
    console.log(paymentResponse);
  })
  .catch(error => {
    console.error(error.response?.data?.error);
  });

Using x402-axios

x402-axios adds a payment interceptor to Axios, so your requests are retried with payment headers automatically.

import { withPaymentInterceptor, decodeXPaymentResponse } from "x402-axios";
import axios from "axios";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

// Create an Axios instance with payment handling
const api = withPaymentInterceptor(
  axios.create({
    baseURL: "https://api.example.com",
  }),
  account,
);

// Make request - payment handled automatically
api
  .get("/paid-endpoint")
  .then(response => {
    console.log(response.data);

    const paymentResponse = decodeXPaymentResponse(
      response.headers["x-payment-response"]
    );
    console.log(paymentResponse);
  })
  .catch(error => {
    console.error(error.response?.data?.error);
  });

Using with MCP (AI Agents)

For AI agents using Model Context Protocol, use x402-mcp:

npm install x402-mcp ai @modelcontextprotocol/sdk
import { experimental_createMCPClient as createMCPClient } from "ai";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { withPayment } from "x402-mcp";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

// Create MCP client with payment capabilities
const mcpClient = await createMCPClient({
  transport: new StreamableHTTPClientTransport(mcpServerUrl),
}).then((client) => withPayment(client, {
  account,
  network: "base-sepolia" // or "base" for mainnet
}));

// Get available tools (both paid and free)
const tools = await mcpClient.tools();

// Use tools with your AI model - payments handled automatically

Get Testnet Tokens

For dev purposes, you could get testnet tokens from faucets: