Skip to content

R402

CI License Rust

Modular Rust SDK for the x402 payment protocol — client signing, server gating, and facilitator settlement over HTTP 402.

r402 provides a production-grade, multi-chain implementation of the x402 protocol with dual-path ERC-3009 / Permit2 transfers, the exact and upto (usage-based) schemes, composable lifecycle hooks, and 44 built-in chain deployments across EVM and Solana.

Crates

Crate Description
r402 crates.io docs.rs Core library — protocol types, scheme traits, facilitator abstractions, and hook system
r402-evm crates.io docs.rs EVM (EIP-155) — ERC-3009 transfer authorization, multi-signer management, nonce tracking
r402-svm crates.io docs.rs Solana (SVM) — SPL token transfers, program-derived addressing
r402-http crates.io docs.rs HTTP transport — Axum payment gate middleware, reqwest client middleware, facilitator client

See also facilitator — a production-ready facilitator server built on r402.

Quick Start

Protect a Route (Server)

use alloy_primitives::address;
use axum::{Router, routing::get};
use r402_evm::{Eip155Exact, USDC};
use r402_http::server::X402Middleware;

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

let app = Router::new().route(
    "/paid-content",
    get(handler).layer(
        x402.with_price_tag(Eip155Exact::price_tag(
            address!("0xYourPayToAddress"),
            USDC::base().amount(1_000_000u64), // 1 USDC (6 decimals)
        ))
    ),
);

Send Payments (Client)

use alloy_signer_local::PrivateKeySigner;
use r402_evm::Eip155ExactClient;
use r402_http::client::{WithPayments, X402Client};
use std::sync::Arc;

let signer = Arc::new("0x...".parse::<PrivateKeySigner>()?);
let x402 = X402Client::new().register(Eip155ExactClient::new(signer));

let client = reqwest::Client::new().with_payments(x402);

let res = client.get("https://api.example.com/paid").send().await?;

Usage-Based Pricing (upto Scheme)

The upto scheme lets the buyer sign a maximum while the resource server picks the final charge at request time (meter reads, token usage, dynamic tiers). The facilitator settles for any value in [0, max]; a final amount of 0 returns no on-chain transaction.

use alloy_primitives::address;
use axum::{Router, response::IntoResponse, routing::post};
use r402_evm::{Eip155Upto, USDC};
use r402_http::server::{UptoActualAmount, X402Middleware};

async fn meter(/* ... */) -> impl IntoResponse {
    let mut response = "result".into_response();
    // Charge 0.125 USDC for this call.
    response.extensions_mut().insert(UptoActualAmount::new("125000"));
    response
}

let layer = X402Middleware::new("https://facilitator.example.com")
    .with_price_tag(Eip155Upto::price_tag(
        address!("0xYourPayToAddress"),
        USDC::base().amount(1_000_000u64), // up to 1 USDC
    ));
let app = Router::new().route("/meter", post(meter).layer(layer));

Handlers opt in by inserting UptoActualAmount into the response extensions; the middleware patches paymentRequirements.amount before forwarding the settle request. Buyers sign with Eip155UptoClient (shares the Permit2 auto-approve plumbing with Eip155ExactClient).

Note: UptoActualAmount is honoured only by SettlementMode::Sequential. Concurrent and background modes start settlement before the handler returns and therefore charge the signed maximum.

Settlement Modes

X402Middleware supports three settlement strategies, configurable via with_settlement_mode():

Sequential (default)

Verify → execute → settle. The safest mode — on-chain settlement only occurs after the handler succeeds, and the Payment-Response header is included in the same HTTP response.

sequenceDiagram
    participant C as Client
    participant S as Server
    participant F as Facilitator
    participant H as Handler

    C->>S: HTTP Request + Payment-Signature
    S->>F: verify(payment)
    F-->>S: VerifyResponse ✓
    S->>H: execute request
    Note over S,H: Balance verified but NOT locked —<br/>handler executing (variable latency)
    H-->>S: response body
    S->>F: settle(payment)
    Note over S,F: On-chain transfer (2–5 s)
    F-->>S: SettleResponse (tx_hash)
    S-->>C: 200 OK + Payment-Response header
Loading

Concurrent

Verify → (settle ∥ execute) → await both. Reduces total latency by overlapping on-chain settlement with handler execution, saving one facilitator round-trip. On handler error the settlement task is detached (fire-and-forget).

sequenceDiagram
    participant C as Client
    participant S as Server
    participant F as Facilitator
    participant H as Handler

    C->>S: HTTP Request + Payment-Signature
    S->>F: verify(payment)
    F-->>S: VerifyResponse ✓
    par settle ∥ execute
        S->>F: settle(payment)
        Note over S,F: On-chain transfer
        F-->>S: SettleResponse (tx_hash)
    and
        S->>H: execute request
        H-->>S: response body
    end
    S-->>C: 200 OK + Payment-Response header
Loading

Background

Verify → spawn settle (fire-and-forget) → execute → return. Settlement runs entirely in the background — the response is returned to the client as soon as the handler completes, without waiting for on-chain confirmation. Ideal for streaming responses (SSE, LLM token streams) where the client should start receiving data immediately. Settlement errors are logged but do not propagate to the caller. Trade-off: the Payment-Response header is not attached since settlement may still be in progress when the response is sent.

sequenceDiagram
    participant C as Client
    participant S as Server
    participant F as Facilitator
    participant H as Handler

    C->>S: HTTP Request + Payment-Signature
    S->>F: verify(payment)
    F-->>S: VerifyResponse ✓
    S-)F: settle(payment) [fire-and-forget]
    S->>H: execute request
    H-->>S: response body (or stream)
    S-->>C: 200 OK (no Payment-Response header)
    Note over S,F: Settlement completes asynchronously
    F-)S: SettleResponse (logged)
Loading

Comparison

Mode Total latency Safety Payment-Response Best for
Sequential verify + handler + settle Settlement only on handler success ✅ Included Standard request/response APIs
Concurrent verify + max(handler, settle) Settlement may occur on handler failure ✅ Included Latency-sensitive endpoints
Background verify + handler Settlement errors are non-fatal (logged) ❌ Not attached SSE / LLM streaming responses

For full manual control over settlement timing, use the composable Paygate API directly with verify_only() + VerifiedPayment::settle().

Design

Aspect Details
Built-in chains 44 — 42 EVM (EIP-155) + 2 Solana
Schemes exact (fixed amount, ERC-3009 + Permit2) + upto (usage-based, Permit2-only, EVM)
Transfer methods Dual path — ERC-3009 transferWithAuthorization + Permit2 proxy
Lifecycle hooks FacilitatorHooks (verify/settle) + ClientHooks (payment creation)
Async model Zero async_trait in core — RPITIT / Pin<Box<dyn Future>>
Facilitator trait Unified — dyn-compatible Box<dyn Facilitator> across all schemes
Wire format V2-only server (CAIP-2 chain IDs, Payment-Signature header)
Settlement errors Explicit — failed settle returns 402 with structured error
Network definitions Decoupled — per-chain crate (r402-evm, r402-svm)
Smart wallets EIP-6492 (counterfactual) + EIP-1271 (deployed) + ERC-2098 (compact signatures)
Linting pedantic + nursery + correctness (deny)

Feature Flags

Each chain and transport crate uses feature flags to minimize compile-time dependencies:

Crate server client facilitator telemetry
r402-http Axum payment gate + facilitator client Reqwest middleware tracing spans
r402-evm Price tag generation EIP-712 / EIP-3009 / Permit2 signing On-chain verify & settle tracing spans
r402-svm Price tag generation SPL token signing On-chain verify & settle tracing spans

Security

See SECURITY.md for disclaimers, supported versions, and vulnerability reporting.

Acknowledgments

License

Licensed under either of:

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project shall be dual-licensed as above, without any additional terms or conditions.


A QNTX open-source project.

QNTX

Code is law. We write both.

About

Rust SDK for the x402 payment protocol.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Sponsor this project

Contributors

Languages