Payments
7. Payments (x402)
7.1 Overview
M2M embeds the x402 protocol to add a settlement layer
on top of the existing stack (compression → security → payments). x402 is
HTTP-native: it uses the long-reserved 402 Payment Required status code and
signed stablecoin authorizations (USDC on EVM chains), requiring no API keys,
accounts, or subscriptions.
The implementation uses the x402-rs
ecosystem and is gated behind the payments cargo feature.
Note: The
paymentsfeature requires a Rust toolchain >= 1.93 to compile (upstream MSRV). The core library remains MSRV 1.88.
7.2 Architecture
Client (payer) M2M Server (payee) Facilitator | | | |--- POST /compress ---------------->| | |<-- 402 + PAYMENT-REQUIRED ---------| | | (b64 PaymentRequired JSON) | | | | | | [sign EIP-712 / EIP-3009 locally] | | | | | |--- POST /compress --------------->|--- POST /verify ----------->| | PAYMENT-SIGNATURE header |<-- isValid: true ------------| | | | |<-- 200 + PAYMENT-RESPONSE ---------|--- POST /settle ----------->| | (b64 SettlementResponse) |<-- success: true -----------|- The client signs a
transferWithAuthorization(EIP-3009) locally; no funds move without its signature and the facilitator cannot alter amount or recipient. - Verification/settlement is delegated to a facilitator over the standardized
REST surface (
/verify,/settle,/supported). Default:https://facilitator.x402.rs. No blockchain infrastructure runs locally.
7.3 Metered Routes
| Route group | Routes | Payment |
|---|---|---|
| Free | /health, /status, /session*, /scan | Never metered |
| Metered | /compress, /compress/auto, /decompress, /message | When configured |
7.4 Pricing Models
Amounts are in atomic USDC units (6 decimals): 1000 = $0.001.
| Model | Semantics |
|---|---|
Flat | Fixed price per request. |
PerToken | Price derived from the X-Max-Tokens request header (per_1k_atomic per 1,000 tokens, rounded down), floored at minimum_atomic. Missing/zero header charges the minimum — metered endpoints can never be accessed for free by omitting the header. |
Per-token pricing mirrors M2M’s design philosophy: routing metadata
(MaxTokens, CostEst) is readable without payload decompression, so usage
can be priced at the middleware layer with zero payload parsing.
7.5 Capability Advertisement
Agents advertise payment support during HELLO/ACCEPT negotiation via the capabilities extension map:
{ "extensions": { "x402": "https://facilitator.x402.rs" }}Peers detect support with capabilities.extensions.contains_key("x402").
7.6 Configuration
Server (payee):
cargo run --features payments -- server \ --pay-to 0x209693Bc6afc0C5328bA36FaF03C514EF312287C \ --payment-network eip155:84532 \ --price-per-1k-tokens 100 --price-minimum 50Client (payer):
use m2m::payments::payer::paying_client;
let client = paying_client_from_env()?; // reads M2M_EVM_PRIVATE_KEYlet res = client.post("https://peer.example/compress") .json(&payload) .send() .await?; // 402 handled automatically7.7 Networks
| Network | CAIP-2 | Asset |
|---|---|---|
| Base Sepolia (dev default) | eip155:84532 | USDC |
| Base mainnet | eip155:8453 | USDC |
7.8 Security Considerations
- Replay protection: each authorization carries a unique 32-byte nonce; EIP-3009 contracts reject reuse.
- Time bounds: authorizations include
validAfter/validBefore. - Trust minimization: the facilitator verifies signatures and simulates before settling; it cannot move funds beyond the signed intent.
- Key custody: payer keys are read from
M2M_EVM_PRIVATE_KEY; use a dedicated low-balance wallet for agents. - Settlement timing: default settles after handler success so failed
requests do not charge payers;
settle_before_executiontrades this for stronger guarantee of payment before work begins.
7.9 Implementation Status
| Component | Status |
|---|---|
| Server middleware (flat pricing) | Stable |
| Server middleware (per-token pricing) | Stable |
Payer client (x402-reqwest) | Experimental |
| Capability advertisement | Stable |
| Self-hosted facilitator | Not implemented (use hosted) |