Skip to content
LogoLogo

Client

Handle 402 responses automatically

The Fetch extension trait adds .send_with_payment() to any reqwest::RequestBuilder—when a server returns 402, it parses the Challenge, signs a stablecoin transfer, and retries with the Credential.

Quick start

use mpp::client::{Fetch, TempoProvider};
use mpp::PrivateKeySigner;
 
let signer = PrivateKeySigner::random();
let provider = TempoProvider::new(signer, "https://rpc.tempo.xyz")?;
 
let response = reqwest::Client::new()
    .get("https://api.example.com/paid")
    .send_with_payment(&provider)
    .await?;
 
println!("Status: {}", response.status());

When the server returns 402, send_with_payment:

  1. Parses the Challenge from the WWW-Authenticate header
  2. Calls provider.pay() to sign a stablecoin transfer
  3. Retries the request with the Credential in the Authorization header

TempoProvider

TempoProvider signs TIP-20 stablecoin transfers on the Tempo blockchain.

use mpp::client::TempoProvider;
use mpp::PrivateKeySigner;
 
let signer: PrivateKeySigner = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
    .parse()?;
 
let provider = TempoProvider::new(signer, "https://rpc.tempo.xyz")?;

With client ID

Attach an identifier to transactions for attribution:

let provider = TempoProvider::new(signer, "https://rpc.tempo.xyz")?
    .with_client_id("my-app");

Middleware

For automatic 402 handling on all requests, use PaymentMiddleware with reqwest-middleware. Requires the middleware feature.

mpp = { version = "0.1", features = ["tempo", "client", "middleware"] }
use mpp::client::{PaymentMiddleware, TempoProvider};
use reqwest_middleware::ClientBuilder;
 
let provider = TempoProvider::new(signer, "https://rpc.tempo.xyz")?;
 
let client = ClientBuilder::new(reqwest::Client::new())
    .with(PaymentMiddleware::new(provider))
    .build();
 
// All requests through this client handle 402 automatically
let response = client.get("https://api.example.com/paid").send().await?;

Multiple providers

MultiProvider wraps multiple payment providers and picks the right one based on the challenge's method and intent:

use mpp::client::{MultiProvider, TempoProvider};
 
let provider = MultiProvider::new()
    .with(TempoProvider::new(signer, "https://rpc.tempo.xyz")?);
 
let response = reqwest::Client::new()
    .get("https://api.example.com/paid")
    .send_with_payment(&provider)
    .await?;

Custom provider

Implement the PaymentProvider trait to add support for custom payment methods:

use mpp::client::PaymentProvider;
use mpp::{PaymentChallenge, PaymentCredential, PaymentPayload, MppError};
 
#[derive(Clone)]
struct MyProvider;
 
impl PaymentProvider for MyProvider {
    fn supports(&self, method: &str, intent: &str) -> bool {
        method == "my_network" && intent == "charge"
    }
 
    async fn pay(
        &self,
        challenge: &PaymentChallenge,
    ) -> Result<PaymentCredential, MppError> {
        let echo = challenge.to_echo();
        Ok(PaymentCredential::new(echo, PaymentPayload::hash("0x...")))
    }
}

Key types

TypeDescription
Fetch (PaymentExt)Extension trait that adds send_with_payment to reqwest::RequestBuilder
MultiProviderWraps multiple providers, routes by method and intent
PaymentMiddlewarereqwest-middleware for automatic 402 handling
PaymentProviderTrait for custom payment method implementations
TempoProviderSigns Tempo stablecoin transfers