preferProtocol defaults to mpp, with x402 available when explicitly requested.
MPP stands for Machine Payments Protocol, an open machine-to-machine payment standard co-authored by Tempo and Stripe. The wire format SELAT detects (a
www-authenticate: Payment ... challenge over HTTP 402) is public; how the SELAT Router signs and settles the Tempo leg internally is proprietary and is not described here.What MPP is
MPP reuses HTTP 402 as a challenge–response handshake built on aPayment HTTP authentication scheme. A server that wants payment returns 402 Payment Required with a WWW-Authenticate: Payment header carrying a challenge; the client fulfils it and retries with an Authorization: Payment credential, and the server returns the resource (with a Payment-Receipt header). The protocol is payment-method-agnostic — the same endpoint can accept stablecoins, cards, or other methods. SELAT uses the Tempo stablecoin method for the MPP rail.
What Tempo is
Tempo is a payments-first, EVM-compatible Layer 1 blockchain incubated by Stripe and Paradigm, with Paradigm’s Matt Huang as CEO. It is purpose-built for stablecoin payments and pairs naturally with MPP, the agent-payments protocol it shipped alongside. SELAT’s chain-normalization layer maps the network totempo:4217 (chain ID 4217) — see normalizeNetwork() in the discovery skill’s chains.mjs.
Tempo’s marketed performance characteristics (high throughput, sub-second finality, stablecoin-denominated gas, sub-cent transfer costs) come from Tempo’s own materials and third-party coverage. Treat them as vendor claims rather than SELAT-verified facts. The specific stablecoin and per-transaction fee SELAT incurs on the Tempo leg are not exposed in selat-pay or the SELAT docs.
How SELAT detects MPP
selat-pay probes the upstream once with noAuthorization header and parses both protocols from the same response. A www-authenticate header can carry several comma-separated challenges (for example X402 requirements="...", Payment id="..."); selat-pay splits them and reads each.
An MPP challenge has the form:
decodeMppChallenge() extracts the quoted params and base64-decodes the request JSON, surfacing the amount, currency, recipient, and methodDetails.chainId. The summarizer composes a network string as method:chainId (e.g. tempo:4217).
The challenge
method value: the code comment shows method="tempo", and the summarizer builds tempo:4217 from method + the request’s chainId. Whether the live router emits the bare tempo token or another form is not pinned down in these sources.Dual-protocol services
Some services gate the MPP path behind an auth header (observed with Nansen). When the first probe surfaces no MPP challenge and there is reason to look for it, selat-pay conditionally fires a second probe withAuthorization: Payment probe to unlock the hidden challenge. It does not send that header blindly — some services reject unknown auth — so the second probe runs only when MPP is wanted and not already found.
How SELAT chooses the rail
After probing, selat-pay picks a route mode:Direct Gateway-batched wins
If the chain offers a direct Circle Gateway-batched option, it is used — it carries no router markup.
MPP wins among routed alternatives
With no direct option, MPP is preferred over routed x402 by default.
routerUrl/proxy?target=...) and sends the hint header x-selat-prefer-protocol: mpp. The CLI describes this routed rail as “erc-3009 or tempo-native MPP, translated by the SELAT Router,” distinct from the direct (Circle Gateway-batched) rail.
Verified vs. proprietary. Verified from code/public sources: the
www-authenticate: Payment detection, the dual-probe behavior, the rail-selection order, the x-selat-prefer-protocol hint, the tempo:4217 identity, and MPP’s HTTP-402 handshake. Left as open items (not asserted): the router’s internal MPP signing/settlement, whether SELAT uses MPP’s streaming “sessions” primitive (selat-pay treats each call as a discrete challenge), the settlement asset and fee on Tempo, and the size of the router’s markup on the MPP rail.