Quickstart
Accept your first x402 payment in 5 minutes
Prerequisites
- Node.js 20+ or Rust 1.88+
- A wallet address to receive payments
- Your FareSide API key (join the waitlist if you don’t have one)
The versions of x402-* crates shown in this guide are indicative. Please check crates.io for the latest available versions.
Choose Your Stack
The examples below use Hono (TypeScript) and Axum (Rust). x402 is a protocol. While Express, Hono, Next.js, Axum are supported out of the box, adding x402-payment-gating to any other framework or language is relatively straightforward.
TypeScript (Hono)
Step 1: Install Dependencies
We use the scoped @x402 packages for v2 support from x402 reference SDK.
npm install hono @hono/node-server @x402/hono @x402/core @x402/evm
Step 2: Create Your Server
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { paymentMiddleware } from "@x402/hono";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { registerExactEvmScheme } from "@x402/evm/exact/server";
const app = new Hono();
// 1. Configure the Facilitator Client with your FareSide API key
const facilitatorClient = new HTTPFacilitatorClient({
url: "https://facilitator.fareside.com/YOUR_API_KEY"
});
// 2. Create the Resource Server and register payment schemes
const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server); // Enable EVM payments
// 3. Configure payment middleware with FareSide facilitator
app.use(
paymentMiddleware(
{
"GET /weather": {
accepts: [
{
scheme: "exact",
price: "$0.01", // Price in USD (converted to USDC)
network: "eip155:84532", // Base Sepolia (CAIP-2 format)
payTo: "0xYourWalletAddress",
},
],
description: "Weather API access",
mimeType: "application/json",
},
},
server,
),
);
// Your paid endpoint
app.get("/weather", (c) => {
return c.json({
location: "San Francisco",
temperature: 68,
conditions: "Sunny",
});
});
serve({ fetch: app.fetch, port: 3000 });
console.log("Server running on http://localhost:3000");
Step 3: Test It
Start your server:
npx tsx server.ts
Make a request without payment:
curl -i http://localhost:3000/weather
You’ll get a 402 Payment Required response. The requirements are returned in the Payment-Required header (base64 encoded), which you can decode with:
echo "<Payment-Required header>" | base64 -d | jq
Decoded header payload example:
{
"x402Version": 2,
"error": "Payment required",
"resource": {
"url": "http://localhost:3000/weather",
"description": "Weather API access",
"mimeType": "application/json"
},
"accepts": [
{
"scheme": "exact",
"network": "eip155:84532",
"amount": "10000", // 0.01 USDC (6 decimals)
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // USDC contract on Base Sepolia
"payTo": "0xYourWalletAddress",
"maxTimeoutSeconds": 300,
"extra": {
"name": "USDC",
"version": "2"
}
}
]
}
Key Fields:
x402Version: Protocol versionresource: Metadata about the protected resourceurl: The resource identifierdescription: Human-readable description of what is being purchasedmimeType: Content type of the resource
accepts: Array of acceptable payment options. The client must choose one to proceedscheme: The payment logic to use (e.g.,"exact"for a fixed amount transfer)network: The blockchain network identifier in CAIP-2 formatamount: The cost in atomic units (e.g.,10000= 0.01 USDC)asset: The token contract address (e.g., USDC address)payTo: The recipient’s wallet addressextra: Scheme-specific parameters (e.g., EIP-712 domain info for EVM tokens)
Rust (Axum)
Step 1: Add Dependencies
[dependencies]
alloy-primitives = "1.4"
axum = "0.8"
serde_json = "1"
tokio = "1"
x402-axum = "1.1"
x402-chain-eip155 = { version = "1.1", features = ["server"] }
x402-types = "1.1"
Step 2: Create Your Server
use axum::{routing::get, Router};
use axum::http::StatusCode;
use axum::response::IntoResponse;
use serde_json::json;
use alloy_primitives::address;
use x402_axum::X402Middleware;
use x402_chain_eip155::{V2Eip155Exact, KnownNetworkEip155};
use x402_types::networks::USDC;
#[tokio::main]
async fn main() {
// Configure FareSide facilitator
let x402 = X402Middleware::try_from(
"https://facilitator.fareside.com/YOUR_API_KEY"
).unwrap();
// Configure USDC on Base Sepolia and your receiving address
let usdc = USDC::base_sepolia();
let wallet = address!("0xYourWalletAddress");
let app = Router::new()
.route("/weather", get(weather_handler).layer(
x402.with_price_tag(
// Create a V2 price tag for 0.01 USDC
V2Eip155Exact::price_tag(
wallet,
usdc.amount(10_000u64) // 0.01 USDC (6 decimals)
)
)
// Description is required for v2 resource metadata
.with_description("Weather API access".to_string())
));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
println!("Server running on http://localhost:3000");
axum::serve(listener, app).await.unwrap();
}
async fn weather_handler() -> impl IntoResponse {
(StatusCode::OK, axum::Json(json!({
"location": "San Francisco",
"temperature": 68,
"conditions": "Sunny"
})))
}
Step 3: Test It
cargo run
Make a request without payment:
curl -i http://localhost:3000/weather
You’ll get a 402 Payment Required response. The requirements are returned in the Payment-Required header (base64 encoded), which you can decode with:
echo "<Payment-Required header>" | base64 -d | jq
Decoded header payload example:
{
"x402Version": 2,
"error": "Payment-Signature header is required",
"resource": {
"url": "http://localhost:3000/weather",
"description": "Weather API access",
"mimeType": "application/json"
},
"accepts": [
{
"scheme": "exact",
"network": "eip155:84532",
"amount": "10000", // 0.01 USDC (6 decimals)
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // USDC contract on Base Sepolia
"payTo": "0xYourWalletAddress",
"maxTimeoutSeconds": 300,
"extra": {
"name": "USDC",
"version": "2"
}
}
]
}
Key Fields:
x402Version: Protocol versionresource: Metadata about the protected resourceurl: The resource identifierdescription: Human-readable description of what is being purchasedmimeType: Content type of the resource
accepts: Array of acceptable payment options. The client must choose one to proceedscheme: The payment logic to use (e.g.,"exact"for a fixed amount transfer)network: The blockchain network identifier in CAIP-2 formatamount: The cost in atomic units (e.g.,10000= 0.01 USDC)asset: The token contract address (e.g., USDC address)payTo: The recipient’s wallet addressextra: Scheme-specific parameters (e.g., EIP-712 domain info for EVM tokens)
Making a Payment (Client Side)
To actually pay for the endpoint, you need an x402-compatible client. Here’s how to test with @x402/fetch:
npm install @x402/fetch @x402/core @x402/evm viem
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client, x402HTTPClient } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
// 1. Setup your wallet
const signer = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
// 2. Create x402 client and register EVM scheme
const client = new x402Client();
registerExactEvmScheme(client, { signer });
// 3. Wrap fetch
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
// 4. Make request - payment is handled automatically
const response = await fetchWithPayment("http://localhost:3000/weather", {
method: "GET",
});
const data = await response.json();
console.log("Weather:", data);
// Check payment receipt
if (response.ok) {
const httpClient = new x402HTTPClient(client);
const receipt = httpClient.getPaymentSettleResponse(
(name) => response.headers.get(name)
);
console.log("Payment settled:", receipt);
}
For more details, see the Making Payments guide.
What Just Happened?
- Client requested
/weatherwithout payment - Server returned
402 Payment Requiredwith payment details - Client created a signed payment payload using the registered EVM scheme
- Client retried the request with
Payment-Signatureheader - FareSide facilitator verified the payment on-chain
- Server delivered the weather data
The payment goes directly to your wallet.
Next Steps
- Setup Guide - Get your FareSide API key
- Hono/Express Integration - Detailed TypeScript examples
- Rust (Axum) Integration - Detailed Rust examples
- Making Payments - Build x402 clients
- Supported Networks - Available chains and tokens