Menu

Explorer & Settings

Tempo Explorer Submit Project
🦀 Rust guide

x402 in Rust

x402 is plain HTTP 402, so adding USDC pay-per-request to an axum service takes only a handler and a facilitator call — and Rust is a favorite for high-throughput facilitators.

How do I use x402 in Rust?

There is no official Rust SDK yet, but x402 is just HTTP 402. On the server, read the X-PAYMENT header in an axum handler (or tower middleware); if missing, return 402 with an "accepts" body describing the price and your wallet, then verify payments via a facilitator's /verify endpoint. Clients follow the same 402-then-retry flow manually with reqwest.

Which approach should you use?

Situation Use Why
One or two routesInline check in the handlerA few lines — no abstraction needed for a single gated endpoint.
Multiple gated routestower middleware layerApply the same 402 check to every route with .layer(...) instead of repeating it.
Building a facilitatorFull verify + settle serviceRust's performance and safety suit a service verifying many on-chain payments per second.
Calling a paid endpointManual retry with reqwestNo client package exists yet — handle the 402 → sign → retry loop yourself.

Server (axum)

Return 402 with payment requirements until a valid X-PAYMENT header arrives, then serve.

// axum handler that requires payment.
// x402 is just HTTP 402, so you can implement it directly in Rust.
use axum::{routing::get, Json, Router, http::{HeaderMap, StatusCode}};
use serde_json::{json, Value};

async fn weather(headers: HeaderMap) -> (StatusCode, Json<Value>) {
    let payment = headers.get("X-PAYMENT").and_then(|v| v.to_str().ok());

    match payment {
        Some(p) if verify_with_facilitator(p).await => {
            // Paid: serve the response
            (StatusCode::OK, Json(json!({ "city": "Tokyo", "forecast": "sunny" })))
        }
        _ => {
            // 402 with payment requirements
            let requirements = json!({
                "scheme": "exact",
                "network": "base-sepolia",  // use "base" in production
                "maxAmount": "10000",         // 0.01 USDC (6 decimals)
                "payTo": "0xYourReceivingWalletAddress",
                "asset": "USDC"
            });
            (StatusCode::PAYMENT_REQUIRED, Json(json!({ "accepts": [requirements] })))
        }
    }
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/weather", get(weather));
    let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

Verifying the payment

A facilitator checks the signed USDC payment on-chain so your server stays simple.

// Verify the payment by POSTing to an x402 facilitator's
// /verify (and later /settle) endpoint over HTTP.
async fn verify_with_facilitator(payment: &str) -> bool {
    // Send the X-PAYMENT payload + requirements to your facilitator,
    // which checks the signed USDC payment on-chain and returns valid=true.
    // Use a hosted facilitator or run your own (several are written in Rust).
    call_facilitator("/verify", payment).await.unwrap_or(false)
}

Middleware for multiple routes

Apply the check to every route with a tower layer instead of repeating it per handler.

// Extract the check into a tower middleware so every route gets it
// without repeating the logic in each handler.
use axum::{middleware::{self, Next}, extract::Request, response::Response};

async fn require_payment(headers: HeaderMap, req: Request, next: Next) -> Response {
    let payment = headers.get("X-PAYMENT").and_then(|v| v.to_str().ok());
    match payment {
        Some(p) if verify_with_facilitator(p).await => next.run(req).await,
        _ => {
            let body = Json(json!({ "accepts": [/* ...requirements */] }));
            (StatusCode::PAYMENT_REQUIRED, body).into_response()
        }
    }
}

let app = Router::new()
    .route("/weather", get(weather))
    .layer(middleware::from_fn(require_payment));

Client (manual retry)

No official Rust client package exists yet, so a caller reads the 402 body and retries with a signed payment itself.

// A Rust client that pays automatically by handling the 402 itself.
// There's no official Rust client SDK yet, so this shows the manual flow —
// most Rust usage of x402 today is on the server/facilitator side.
let resp = reqwest::get("http://localhost:8080/weather").await?;

if resp.status() == reqwest::StatusCode::PAYMENT_REQUIRED {
    let body: serde_json::Value = resp.json().await?;
    let requirement = &body["accepts"][0];
    // Sign a USDC payment for the requirement above, then retry with the
    // signed payload in the X-PAYMENT header.
    let signed = sign_payment(requirement);
    let resp = reqwest::Client::new()
        .get("http://localhost:8080/weather")
        .header("X-PAYMENT", signed)
        .send()
        .await?;
}

Troubleshooting

Handler always returns 402, even after paying

Why: verify_with_facilitator is checking the wrong field, or the facilitator call is failing silently and defaulting to false via unwrap_or.

Fix: Log the facilitator’s raw response once during development instead of collapsing errors straight into a bool.

"insufficient funds" on a testnet

Why: Your Base Sepolia test wallet has no faucet USDC (or no ETH for gas, depending on the facilitator’s settlement path).

Fix: Fund the address from a Base Sepolia USDC faucet before retrying — this never touches real money.

Amount charged looks 1,000,000x too big/small

Why: USDC uses 6 decimals. maxAmount must be an integer string in base units ("10000" = $0.01), not a dollar amount.

Fix: Use the free base-unit converter (linked below) to compute the integer.

X-PAYMENT header missing on the server

Why: A reverse proxy, load balancer or CDN in front of your axum service is stripping custom headers before they reach the handler.

Fix: Check the proxy config allows X-PAYMENT through, and log the full HeaderMap at the top of the handler to confirm what actually arrives.

Get amounts right with the free base-unit converter.

Rust x402 projects

Real open-source implementations · stars live from GitHub.

qntx/machi

Agent behavior that compiles

⭐ 566
x402-rs/x402-rs

x402 payments in Rust: verify, settle, and monitor payments over HTTP 402 flows

⭐ 280
xpaysh/awesome-x402

🚀 Curated list of x402 resources: HTTP 402 Payment Required protocol for blockchain payments, crypto micropayments, AI agents, API monetization. Includes SDKs (TypeScript, Python, Rust), examples, facilitators (Coinbase, Cloudflare), MCP integration, tutorials. Accept USDC payments with one line of code. Perfect for AI agent economy.

⭐ 264
qntx/facilitator

Production-ready x402 facilitator server.

⭐ 149
qntx/r402

Rust SDK for the x402 payment protocol.

⭐ 149
bolivian-peru/os-moda

An operating system built for AI agents — talk to your NixOS server instead of SSH-ing in. Typed, audited tool access with atomic rollback on every change. Research-grade; run it on a disposable box, not production.

⭐ 112
AlephantAI/AIephant-AI-Agent-Gateway

Alephant is an open-source AI Agent Gateway for routing, tracking, and controlling LLM usage across AI agents, members, and workflows, and for publishing agent capabilities as paid endpoints with x402 and MPP payment rails.

⭐ 107
solana-foundation/pay-kit

Building blocks for Agentic payments (x402, MPP, AP2) for TypeScript, Rust, Go, Python, Ruby, PHP, Lua, Kotlin and Swift.

⭐ 69

Test for free on Base Sepolia, then use network: "base" in production. For other languages see the SDK guide, or the full tutorial.

Frequently asked questions

Is there a Rust SDK for x402?

x402 is an open HTTP protocol and there are real Rust implementations, including production-grade facilitator servers. There is no official Rust client SDK yet, but because the protocol is plain HTTP 402, you can implement both server and client directly with a framework like axum: return 402 with payment requirements, verify through a facilitator, then serve the response. The Rust projects below are open-source starting points.

How do I gate an axum route behind a payment?

Read the X-PAYMENT header in your handler. If it is missing or invalid, respond with StatusCode::PAYMENT_REQUIRED (402) and an "accepts" body describing the price, network, asset (USDC) and your receiving address. If the payment verifies through a facilitator, return your normal response. Extract this into a tower middleware layer (shown above) to apply it across routes.

How does a Rust client pay an x402 endpoint?

There is no official Rust client package yet, so a client handles the 402 manually with reqwest: make the request, and if the response status is 402, read the accepts array from the JSON body, sign a USDC payment for one of the listed requirements, then retry with the signed payload in the X-PAYMENT header.

Why use Rust for x402?

Rust is a strong fit for facilitators and high-throughput payment gateways where performance and memory safety matter — verifying and settling many small on-chain payments per second. Several open-source facilitators are written in Rust for exactly this reason.

axum or actix-web for x402?

Both work the same way since x402 is protocol-level, not framework-specific: check a header, return 402 with a JSON body, or run the handler after verification. axum’s tower middleware makes the reusable-layer pattern shown above especially clean, but the same logic ports directly to actix-web extractors.

Can I test the Rust x402 flow for free?

Yes. Set the network to "base-sepolia" and fund a test wallet from a free faucet. The 402 → pay → 200 flow is identical to mainnet; switch the network to "base" when you go live.

More: all SDKs · Python · Node.js · Go