Clients • 6 min read
Making Payments
Learn how to build x402 clients that can pay for services
x402 clients automatically handle the payment flow:
- Make a request to a protected endpoint
- Receive
402 Payment Requiredwith payment details - Create and sign a payment transaction
- Retry the request with payment proof
- 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:
- Base Sepolia Faucet to get native Base Sepolia ETH
- Solana Devnet Faucet to get Solana Devnet SOL
- Circle Faucet to get Circle’s test tokens (USDC, EURC,…)