mpay
Rust SDK for the Machine Payments Protocol (MPP) - an implementation of the "Payment" HTTP Authentication Scheme.
Design Principles
- Protocol-first — Core types (
Challenge,Credential,Receipt) map directly to HTTP headers - Zero-copy parsing — Efficient header parsing without unnecessary allocations
- Pluggable methods — Payment networks are feature-gated
- Minimal dependencies — Core has minimal deps; features add what you need
- Intent = Schema, Method = Implementation — Intents define shared request schemas; methods implement verification
Core Types
| Type | Role | HTTP Header |
|---|---|---|
PaymentChallenge |
Server's payment request | WWW-Authenticate: Payment ... |
ChargeRequest |
Typed request schema (inside challenge) | Base64 in request= param |
PaymentCredential |
Client's payment proof | Authorization: Payment ... |
Receipt |
Server's confirmation | Payment-Receipt: ... |
Traits
| Trait | Side | Purpose |
|---|---|---|
ChargeMethod |
Server | Verify credentials against ChargeRequest |
PaymentProvider |
Client | Create credentials from challenges |
Quick Start
Parse a Challenge (Server → Client)
use ;
let header = r#"Payment realm="api.example.com", id="abc123", method="tempo", intent="charge", request="eyJhbW91bnQiOiIxMDAwIn0""#;
let challenge = parse_www_authenticate?;
println!;
println!;
Create a Credential (Client → Server)
use ;
// After parsing a challenge, create a credential with the echo
let credential = with_source;
let auth_header = format_authorization?;
Parse a Receipt (Server → Client)
use ;
let receipt = parse_receipt?;
assert!;
API Reference
Core
PaymentChallenge
A parsed payment challenge from a WWW-Authenticate header.
use ;
let challenge = PaymentChallenge ;
let header = format_www_authenticate?;
let parsed = parse_www_authenticate?;
PaymentCredential
The credential sent in the Authorization header.
use ;
// After parsing a challenge, create the credential
let credential = with_source;
let header = format_authorization?;
let parsed = parse_authorization?;
Receipt
Payment receipt returned after successful verification.
use ;
let receipt = success;
// Format using standalone function
let header = format_receipt?;
// Or use the method directly
let header = receipt.to_header?;
let parsed = parse_receipt?;
Intent Schemas
Intent schemas define shared request fields per spec:
use ChargeRequest;
let request = ChargeRequest ;
Server-Side Handler
Use Mpay to bind method, realm, and secret_key once:
use ;
// Create provider and method
let provider = tempo_provider?;
let method = new;
// Create handler with bound secret_key
let payment = new;
// Generate challenge (secretKey already bound)
let challenge = payment.charge_challenge?;
// Verify a payment
let receipt = payment.verify.await?;
Client-Side Traits
PaymentProvider creates credentials for challenges:
use ;
let provider = new?;
// Check support
assert!;
// Create credential
let credential = provider.pay.await?;
Multiple Payment Methods
Use MultiProvider to handle multiple payment methods:
use ;
let provider = new
.with;
// .with(StripeProvider::new(api_key))
// .with(OtherProvider::new(...))
// Automatically picks the right provider based on challenge.method
let resp = client.get.send_with_payment.await?;
Install
[]
= "0.2"
Feature Flags
| Feature | Description |
|---|---|
client |
Client-side payment providers (PaymentProvider trait, Fetch extension) |
server |
Server-side payment verification (ChargeMethod trait) |
tempo |
Tempo blockchain support (includes evm) - requires git patch (see below) |
evm |
Shared EVM utilities (Address, U256, parsing) |
http |
HTTP client support with Fetch extension trait (implies client). For Tempo payments, combine with tempo: features = ["http", "tempo"] |
middleware |
reqwest-middleware support with PaymentMiddleware (implies client) |
utils |
Hex/random utilities for development and testing |
Common configurations
# Core only (parsing/formatting) - works out of the box
= "0.2"
# With Tempo support (requires git patch)
= { = "0.2", = ["tempo"] }
# Server app with Tempo
= { = "0.2", = ["server", "tempo"] }
# Client app with Tempo
= { = "0.2", = ["client", "tempo"] }
Using the tempo feature
The tempo feature requires Tempo's internal crates which are not published to crates.io.
Add this patch to your Cargo.toml:
[]
= { = "https://github.com/tempoxyz/tempo" }
= { = "https://github.com/tempoxyz/tempo" }
HTTP Client Support
Extension Trait (recommended)
Enable the client feature for the Fetch trait:
use ;
let provider = new?;
let resp = client
.get
.send_with_payment
.await?;
Middleware (automatic)
Enable the middleware feature for automatic 402 handling:
use ;
use ClientBuilder;
let provider = new?;
let client = new
.with
.build;
Examples
See the examples/ directory for integration patterns with common HTTP libraries:
Development
License
MIT OR Apache-2.0