Skip to main content

r402_http/client/
mod.rs

1//! Reqwest middleware for automatic [x402](https://www.x402.org) payment handling.
2//!
3//! This crate provides a [`X402Client`] that can be used as a `reqwest` middleware
4//! to automatically handle `402 Payment Required` responses. When a request receives
5//! a 402 response, the middleware extracts payment requirements, signs a payment,
6//! and retries the request with the payment header.
7//!
8//! ## Registering Scheme Clients
9//!
10//! The [`X402Client`] uses a plugin architecture for supporting different payment schemes.
11//! Register scheme clients for each chain/network you want to support:
12//!
13//! - **`V2Eip155ExactClient`** (from `r402-evm`) - EIP-155 chains, "exact" payment scheme
14//! - **`V2SolanaExactClient`** (from `r402-svm`) - Solana chains, "exact" payment scheme
15//!
16//! See [`X402Client::register`] for more details on registering scheme clients.
17//!
18//! ## Payment Selection
19//!
20//! When multiple payment options are available, the [`X402Client`] uses a `PaymentSelector`
21//! to choose the best option. By default, it uses `FirstMatch` which selects the first
22//! matching scheme. You can implement custom selection logic by providing your own selector.
23//!
24//! See [`X402Client::with_selector`] for custom payment selection.
25
26pub mod hooks;
27mod middleware;
28
29pub use hooks::ClientHooks;
30pub use middleware::{X402Client, parse_payment_required};
31use reqwest::{Client, ClientBuilder};
32use reqwest_middleware as rqm;
33
34/// Trait for adding x402 payment handling to reqwest clients.
35///
36/// This trait is implemented on [`Client`] and [`ClientBuilder`], allowing
37/// you to create a reqwest client with automatic x402 payment handling.
38pub trait ReqwestWithPayments<A, S> {
39    /// Adds x402 payment middleware to the client or builder.
40    ///
41    /// # Arguments
42    ///
43    /// * `x402_client` - The x402 client configured with scheme handlers
44    ///
45    /// # Returns
46    ///
47    /// A builder that can be used to build the final client.
48    fn with_payments(self, x402_client: X402Client<S>) -> ReqwestWithPaymentsBuilder<A, S>;
49}
50
51impl<S> ReqwestWithPayments<Self, S> for Client {
52    fn with_payments(self, x402_client: X402Client<S>) -> ReqwestWithPaymentsBuilder<Self, S> {
53        ReqwestWithPaymentsBuilder {
54            inner: self,
55            x402_client,
56        }
57    }
58}
59
60impl<S> ReqwestWithPayments<Self, S> for ClientBuilder {
61    fn with_payments(self, x402_client: X402Client<S>) -> ReqwestWithPaymentsBuilder<Self, S> {
62        ReqwestWithPaymentsBuilder {
63            inner: self,
64            x402_client,
65        }
66    }
67}
68
69/// Builder for creating a reqwest client with x402 middleware.
70#[allow(missing_debug_implementations)] // generic A may not implement Debug
71pub struct ReqwestWithPaymentsBuilder<A, S> {
72    inner: A,
73    x402_client: X402Client<S>,
74}
75
76/// Trait for building the final client from a [`ReqwestWithPaymentsBuilder`].
77pub trait ReqwestWithPaymentsBuild {
78    /// The type returned by [`ReqwestWithPaymentsBuild::build`]
79    type BuildResult;
80    /// The type returned by [`ReqwestWithPaymentsBuild::builder`]
81    type BuilderResult;
82
83    /// Builds the client, consuming the builder.
84    fn build(self) -> Self::BuildResult;
85
86    /// Returns the underlying reqwest client builder with middleware added.
87    fn builder(self) -> Self::BuilderResult;
88}
89
90impl<S> ReqwestWithPaymentsBuild for ReqwestWithPaymentsBuilder<Client, S>
91where
92    X402Client<S>: rqm::Middleware,
93{
94    type BuildResult = rqm::ClientWithMiddleware;
95    type BuilderResult = rqm::ClientBuilder;
96
97    fn build(self) -> Self::BuildResult {
98        self.builder().build()
99    }
100
101    fn builder(self) -> Self::BuilderResult {
102        rqm::ClientBuilder::new(self.inner).with(self.x402_client)
103    }
104}
105
106impl<S> ReqwestWithPaymentsBuild for ReqwestWithPaymentsBuilder<ClientBuilder, S>
107where
108    X402Client<S>: rqm::Middleware,
109{
110    type BuildResult = Result<rqm::ClientWithMiddleware, reqwest::Error>;
111    type BuilderResult = Result<rqm::ClientBuilder, reqwest::Error>;
112
113    fn build(self) -> Self::BuildResult {
114        let builder = self.builder()?;
115        Ok(builder.build())
116    }
117
118    fn builder(self) -> Self::BuilderResult {
119        let client = self.inner.build()?;
120        Ok(rqm::ClientBuilder::new(client).with(self.x402_client))
121    }
122}