A deep comparison of x402 upto and MPP Sessions: how they handle variable-cost payments, micropayment streaming, escrow vs allowance models, and when to choose each architecture for machine-to-machine payments.
TL;DR
x402 upto and MPP Sessions (I use Tempo Session here as example) solve the same practical problem: how to charge a client exactly for what they actually consumed when the final cost is unknown in advance, while also reducing the number of transactions. But they solve it at different abstraction layers and with fundamentally different settlement architectures.
x402
uptois an “open check” with a maximum amount. The client signs a one-time authorization to charge up to X. The server delivers the service, calculates the actual cost, and performs one on-chain transaction for the real amount. This model lives entirely inside a single HTTP request-response cycle, uses Permit2, and requires no escrow.MPP Tempo Sessions is a payment channel (state channel). The client deposits funds into an on-chain escrow contract, then exchanges off-chain EIP-712 “vouchers” with the server, each representing a cumulative amount. The channel stays alive for a long time, can contain unlimited micropayments, and requires exactly two on-chain transactions for all of them: opening and closing.
Simplified:
x402 upto= one HTTP request with an unknown final price.
MPP Sessions= a long-lived streaming connection where payments flow in sync with data.
Session Lifecycle
x402 upto
The upto scheme exists within a normal HTTP request-response cycle extended with HTTP 402 status.
Lifecycle:
-
Challenge. The client makes a request, and the server responds with
402 Payment RequiredcontainingPaymentRequirements, specifyingscheme: "upto", recipient address, token, network, maximum timeout, and most importantlyamount— the upper limit the server wants authorization for. -
Signature. The client creates a Permit2
permitWitnessTransferFrommessage wherepermitted.amountequals the maximum requested amount,witness.tois the recipient address,witness.facilitatoris the facilitator address (published by the server via/supported), and setsdeadlineandvalidAfter. Then signs it with EIP-712. -
Paid request. The client repeats the HTTP request, attaching
PAYMENT-SIGNATUREwith the payload (signature + Permit2 authorization parameters). - Verification. The facilitator verifies the signature, Permit2 allowance, client balance, signature validity window, and token/network consistency. No funds move at this stage.
- Service execution. The server processes the request (generates tokens, returns a file, runs computation) and calculates the actual final cost.
-
Settlement. The server sends
PaymentRequirementsto the facilitator again, now with the actualamount(this is the key feature of the scheme: the same field means different things in different phases — maximum during verification, actual charge during settlement). The facilitator callsx402UptoPermit2Proxy.settle(...)using the real amount, which must be≤the signed maximum. If the actual amount is zero, no on-chain transaction happens at all — the authorization simply expires unused.
One signature = one settlement.
upto explicitly forbids multi-settlement and streaming: the same signature cannot be reused because of Permit2 nonce semantics. If another charge is needed, a new signature is required — meaning a new HTTP request.
MPP Tempo Sessions
A Tempo session is a full protocol with a dedicated on-chain TempoStreamChannel contract and multiple states.
Lifecycle:
-
Challenge. The server returns
402withWWW-Authenticate: Payment method="tempo" intent="session". It includes price per unit of consumption (amount+unitType, e.g.25base units perllm_token), recommended deposit (suggestedDeposit), escrow contract address, and optionallychannelIdif the server proposes reusing an existing channel. -
Open. The client sends an on-chain transaction
open(payee, token, deposit, salt, authorizedSigner). The contract creates a channel with deterministicchannelId = keccak256(payer, payee, token, salt, authorizedSigner, contract, chainId)and locks the deposit. The client sends the signed transaction to the server together withaction="open"and an initial voucher withcumulativeAmount = 0. -
Streaming + vouchers. The server begins streaming content (typically SSE or chunked). As consumption grows, the client signs EIP-712 vouchers with monotonically increasing cumulative amounts:
100 → 250 → 400 → .... Vouchers are sent over the same HTTP URI (often viaHEADrequests), with no separate control plane. Each voucher is only a few hundred bytes and verifies in microseconds. -
Top-up (optional). If the session lasts longer than expected and deposit runs low, the client can call on-chain
topUp()and continue without closing the channel. Tempo even defines an SSE eventpayment-need-voucherto notify the client that balance is exhausted. -
Settle (optional, many times). The server may call
settle(channelId, cumulativeAmount, signature)at any time to withdraw already earned funds without closing the channel. This is a major difference fromupto: partial on-chain settlements during a live session are allowed. -
Cooperative close. The client sends
action="close"with the final voucher. The server callsclose(), and the contract transfers the delta (cumulativeAmount - already_settled) to the payee, refunds the remainder to the payer, and finalizes the channel. -
Forced close (client protection). If the server becomes silent and does not close the channel, the client calls
requestClose(), waits through a grace period (15 minutes in the reference implementation), then callswithdraw()to reclaim remaining funds. The server has a window to submit the final voucher.
Key detail: vouchers are cumulative. This means the client does not need to track history — it simply signs “total owed so far is X.” Once the server receives a newer voucher, all previous ones can be discarded. During settlement, the contract computes delta as cumulativeAmount - channel.settled, naturally preventing replay and double-spending.
Table of Key Differences
| Parameter | x402 upto
|
MPP Tempo Sessions |
|---|---|---|
| Settlement model | Allowance (Permit2) — funds stay with client until settlement | Escrow — funds locked in contract |
| Protocol unit | Single HTTP request | Long-lived channel across many requests |
| On-chain tx per session | 0 or 1 (final transfer only) | Minimum 2 (open + close), plus optional settle()
|
| Payment granularity | One final amount per request | Unlimited vouchers (per-token, per-byte, per-ms) |
| Payment confirmation speed | ~On-chain confirmation | Microseconds (voucher signature verification) |
| Client signature type | EIP-712 Permit2 Witness Transfer | EIP-712 Voucher (channelId + cumulativeAmount) |
| Time limits | Strict: validAfter + deadline
|
No expiry — channel lives until explicitly closed |
| Authorization reuse | Forbidden (single-use nonce) | Built-in: each new voucher replaces previous |
| Partial settlements during session | Not supported | Yes, via settle()
|
| Client protection if server silent | Signature expires after deadline |
requestClose + grace period + withdraw
|
| Server protection | Signature + allowance/balance check; client may empty wallet before settlement | Funds already in escrow |
| Server state requirements | Minimal, nearly stateless | Requires persistent accounting |
| Ideal use case | REST endpoint with variable pricing | Streaming, agents, high-frequency APIs |
Architectural Differences That Actually Matter
Escrow vs Allowance Is Not Style — It Is Risk Allocation
In x402 upto, funds physically remain in the client wallet until settlement. The server relies on:
- valid signature,
- sufficient balance at settlement time,
- Permit2 allowance not revoked.
Between verification and settlement there is a window where the client can technically withdraw funds. In practice this window is short (seconds), but for high-stakes scenarios it is still a risk.
In MPP Sessions, funds are already in escrow. Once the server has a signed voucher, it is guaranteed to settle it — nobody else can withdraw those funds. This is a fundamentally different guarantee model, paid for with deposits and at least two on-chain transactions.
Why Sessions Can Handle a Million Payments per Second and upto Cannot
Verifying one voucher in Sessions is just ECDSA signature verification plus comparing cumulativeAmount > highestVoucherAmount. That takes microseconds. A server can process thousands of vouchers per second on one channel without touching blockchain. Heavy chain interaction happens only on open/close.
In upto, every payment requires a new Permit2 nonce and new signature. upto is designed for cases where neither client nor server knows in advance how much will ultimately be charged. It enables a complex process to run and then settle afterward. MPP Sessions, by contrast, allows continuous process control.
You could implement more complex channel-like logic in x402 too — but why, if MPP Sessions already provides it?
Cumulative Semantics — Small but Elegant
In MPP Sessions, a voucher specifies total amount paid so far, not incremental payment. This gives three properties:
- Idempotency. Re-submitting the same voucher changes nothing.
- Replay protection without nonce. Any older voucher is rejected because it was already accepted or superseded.
- Resilience to network flakiness. Lost vouchers do not matter — the next one covers everything.
In upto, this problem is solved differently: single-use signatures and Permit2 nonce semantics. But the scenario itself is much simpler — one signature lives for one request only.
Server State
upto is nearly stateless — the server may store nothing between verification and settlement except the signature itself.
Sessions require persistent crash-safe accounting (draft-tempo-session explicitly requires writing spent into durable storage before delivering service, otherwise a crash may cause unpaid content delivery). This is serious operational complexity if your architecture was previously stateless.
Client Protection: deadline vs Grace Period
In upto, the client is protected by signature expiry: after deadline, the facilitator can no longer charge anything. But while it remains valid, the client cannot revoke it except by spending funds or calling Permit2.invalidateNonces.
In MPP Sessions, even without server cooperation, the client can always reclaim funds: requestClose → wait 15 min → withdraw. This costs 2–3 on-chain calls and some waiting, but guarantees exit.
Pros and Cons
x402 upto
Pros:
- Simplest integration on top of any REST API.
- Zero operational overhead: stateless server, no background settlement tasks.
- No deposit — client funds are not locked.
- Fits naturally into existing HTTP semantics and HTTP 402.
- Uses canonical Permit2 trusted across the EVM ecosystem.
- Minimal setup: client only needs to approve Permit2 once.
Cons:
- Not suitable for streaming: impossible to pay per-token in real time.
- Strictly single-use authorization — multi-settlements are out of scope.
- Server pays gas for every settlement separately.
- Client must trust server’s cost calculation within the signed maximum.
- Between signing and settlement, client may theoretically empty wallet.
- Requires client funds to remain in wallet rather than escrow.
MPP Tempo Sessions
Pros:
- True streaming: payment synchronized with data flow.
- Gas amortization: thousands of micropayments fit into two on-chain tx.
- Strong guarantees for server (funds already escrowed).
- Built-in forced close protects clients.
- Supports delegated
authorizedSigner: hot wallet can sign while cold wallet deposits. - Clean top-up model without closing channel.
- Uses IETF-compatible Payment Auth scheme — not just a Web3 hack.
Cons:
- Two mandatory on-chain steps: open and close. Expensive for short sessions.
- Deposit locks client capital.
- Requires separate contract and infrastructure (indexing, workers, crash-safe accounting).
- Server must maintain persistent per-channel state.
- Harder to debug: more states, more failure scenarios.
- Bound to a specific network (Tempo chain in this case); cross-chain is harder.
When to Choose Which
Choose upto if:
- You have a classic REST/RPC API where one request = one response.
- Request price is variable but resolved in one atomic operation.
- You do not want escrow/state-channel infrastructure.
- Your clients do not want locked deposits.
- Payment frequency is low.
- You want to monetize an existing API quickly with minimal changes.
Choose Sessions if:
- You stream content (SSE, WebSocket, chunked) and want payment synchronized with bytes.
- Agents/bots interact hundreds of times per minute.
- Gas cost for on-chain settlement becomes comparable to service price.
- You need strong guarantees that client payment is secured.
- You are building AI inference marketplaces with millisecond billing latency.
- Your architecture can support stateful servers.
Hybrid is also valid. Nothing prevents one service from supporting both upto for one-shot API requests and Sessions for streaming endpoints. At the 402 challenge level, you simply offer multiple schemes and let the client choose.
Conclusion
upto and Sessions are not competitors — they are complementary tools at different points on the “frequency vs complexity” spectrum.
-
uptois the evolution of the HTTP request. You add the ability to charge an amount only known after processing, while everything else stays familiar. - Sessions are the evolution of payment infrastructure. You establish a dedicated payment channel where money movement becomes nearly free, but inherit the complexity of state channels.
For most AI APIs today — where “one prompt = one response” — upto wins because of simplicity. But once you seriously enter machine-to-machine economies, where agents live inside APIs for hours and consume streams continuously, MPP Sessions becomes the only viable option.
A simple mnemonic:
upto= “Charge me whatever it costs, within the check limit.”
MPP Sessions= “I put money in the vault — take vouchers as needed until I say stop.”
Top comments (0)