Rust SDK
Gate any HTTP route for stablecoin payments with solana-pay-kit — one config, a dual-protocol axum gate that advertises both MPP and x402.
solana-pay-kit is stablecoin payment gating for HTTP services in Rust. Pick a currency, give it your wallet address, and gate an axum route — an unpaid request gets a 402 Payment Required carrying both the MPP and x402 challenges, and the client pays with whichever protocol it supports. You do not need to know anything about Solana to use it.
Install
[dependencies]
solana-pay-kit = { version = "0.1", features = ["axum"] }
axum = "0.8"
tokio = { version = "1", features = ["full"] }The axum feature pulls in the paid_get / paid_post gate and implies server-side verification for both protocols. For a single protocol, use default-features = false with features = ["mpp"] (or ["x402"]).
Quick start
Create the gate
PayKit::new takes a PayKitConfig: the recipient wallet, the network, and an RPC URL. Beyond that it is zero-config — a published demo recipient and the hosted Surfpool sandbox let you run it immediately.
use axum::Router;
use solana_pay_kit::{paid_get, PayKit, PayKitConfig, Payment};
// The verified payment lands in the handler.
async fn quote(payment: Payment) -> String {
format!("quote — paid {} via {}", payment.amount, payment.protocol)
}let pay = PayKit::new(PayKitConfig { recipient: "CXhrFZJLKqjzmP3sjYLcF4dTeXWKCy9e2SXXZ2Yo6MPY".to_string(), network: "localnet".to_string(), rpc_url: Some("https://402.surfnet.dev:8899".to_string()), ..Default::default()}).expect("valid config");// `paid_get(handler, price, &pay)` settles the 402 (MPP or x402, the// client's choice) before the handler runs.let app = Router::new().route("/quote", paid_get(quote, "0.01", &pay));Gate your routes
paid_get(handler, price, &pay) (and paid_post) returns an axum MethodRouter. If no valid payment was sent it halts with a 402 carrying both challenges; when one was, it verifies and settles it, sets the settlement header, and runs your handler. The verified Payment is available as a handler extractor.
Run it
cargo run --features axumMake a paid call
Hit the route with the pay CLI — it walks the user through approval and pays in USDC:
pay curl http://127.0.0.1:4567/quoteRust also ships the paying side, via the protocol-layer crate re-exported at solana_pay_kit::mpp. Read the 402 challenge, sign a credential, and replay the request with it:
use solana_pay_kit::mpp::client::{build_credential_header, parse_challenge};
use solana_pay_kit::mpp::solana_keychain::memory::MemorySigner;
use solana_pay_kit::mpp::solana_rpc_client::rpc_client::RpcClient;// 1. Parse the MPP charge challenge from the 402 `WWW-Authenticate` header.let challenge = parse_challenge(www_authenticate)?;// 2. Sign a payment credential and replay the request with it.let authorization = build_credential_header(signer, rpc, &challenge).await?;let res = reqwest::Client::new() .get("https://api.example.com/quote") .header("Authorization", authorization) .send() .await?;println!("{}", res.text().await?);See Client for the auto-pay guardrails (spending cap, network pin).
No Rust at all — the pay CLI is a client for any 402-gated route, handling wallet, signing, and the payment retry for you:
brew install pay # or: npm install -g @solana/pay
pay --sandbox curl https://debugger.pay.sh/mpp/quote/AAPLNext steps
- Payment schemes — fixed charge, metered usage (
upto), and batch-settlement. - Pricing — fixed and per-request prices.
- Client — the paying side.
- Signers — local keys and fee sponsorship.
- Errors — error types and the boot-time safety rails.