Skip to main content

Crate x402_axum

Crate x402_axum 

Source
Expand description

Axum middleware for enforcing x402 payments on protected routes.

This middleware validates incoming payment headers using a configured x402 facilitator, and settles valid payments either before or after request execution (configurable).

Returns a 402 Payment Required response if the request lacks a valid payment.

§Example Usage

use alloy_primitives::address;
use axum::{Router, routing::get};
use axum::response::IntoResponse;
use http::StatusCode;
use x402_axum::X402Middleware;
use x402_chain_eip155::{KnownNetworkEip155, V1Eip155Exact};
use x402_types::networks::USDC;

let x402 = X402Middleware::new("https://facilitator.x402.rs");

let app: Router = Router::new().route(
    "/protected",
    get(my_handler).layer(
        x402.with_price_tag(V1Eip155Exact::price_tag(
            address!("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"),
            USDC::base_sepolia().parse("0.01").unwrap(),
        ))
    ),
);

async fn my_handler() -> impl IntoResponse {
    (StatusCode::OK, "This is VIP content!")
}

See X402Middleware for full configuration options. For low-level interaction with the facilitator, see facilitator_client::FacilitatorClient.

§Protocol Support

Supports both V1 and V2 x402 protocols through the PaygateProtocol trait. The protocol version is determined by the price tag type used.

§Dynamic Pricing

For dynamic pricing based on request context, use X402Middleware::with_dynamic_price:

use axum::Router;
use axum::routing::get;
use axum::response::IntoResponse;
use axum::http::StatusCode;
use alloy_primitives::address;
use x402_axum::X402Middleware;
use x402_chain_eip155::KnownNetworkEip155;
use x402_chain_eip155::V1Eip155Exact;
use x402_types::networks::USDC;

let x402 = X402Middleware::new("https://facilitator.x402.rs");

let app: Router = Router::new().route(
    "/protected",
    get(my_handler).layer(
        x402.with_dynamic_price(|headers, uri, base_url| {
            // Compute price based on request context
            let is_premium = headers
                .get("X-User-Tier")
                .and_then(|v| v.to_str().ok())
                .map(|v| v == "premium")
                .unwrap_or(false);

            let amount = if is_premium { "0.005" } else { "0.01" };
            async move {
                vec![V1Eip155Exact::price_tag(address!("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), USDC::base_sepolia().parse(amount).unwrap())]
            }
        })
    ),
);

async fn my_handler() -> impl IntoResponse {
    (StatusCode::OK, "This is a VIP content!")
}

§Settlement Timing

By default, settlement occurs after the request is processed. You can change this behavior:

§Configuration Notes

Re-exports§

pub use layer::X402LayerBuilder;
pub use layer::X402Middleware;
pub use paygate::DynamicPriceTags;
pub use paygate::PaygateProtocol;
pub use paygate::PriceTagSource;
pub use paygate::StaticPriceTags;

Modules§

facilitator_client
A x402_types::facilitator::Facilitator implementation that interacts with a remote x402 Facilitator over HTTP.
layer
Axum middleware for enforcing x402 payments on protected routes.
paygate
Unified Paygate implementation supporting both V1 and V2 x402 protocols.