Agentic week: x402 grew a payment lifecycle
Three changes merged into x402 this week and all of them attack the same assumption: that a payment is one request, one signature, one settlement.
Last week the theme was constraints. Spending caps, a non-terminal settlement state, infrastructure-level limits. This week the theme is time. Every substantive change merged between 21 and 28 August moves some part of the payment out of the single HTTP round trip it used to live in — before the handler, after the handler, or hours later, out of band.
That is what it looks like when a payment rail stops being a paywall primitive and starts being a payment system. The releases carrying the week are @x402/core 2.24.0 on npm and x402 2.21.0 on PyPI, both published on 27 August. For scale: @x402/core recorded 1,023,046 npm downloads in the thirty days to 27 August, up from the 871,818 we cited a week earlier.
1. auth-capture v1.1 removed the flag and bound the authorizer
PR #3197 merged on 25 August and rewrote the auth-capture scheme specification — 782 lines added, 215 removed, two files. The TypeScript and Go client followed on 27 August across 30 files. Both are marked breaking.
The old design selected between two-phase and single-shot behaviour with a boolean, extra.autoCapture. That flag is gone. extra.paymentFlow is now the only flow selector, and the scheme declares two:
- Escrow (the scheme default) — hold first, finalise after the resource. Synchronous and stateless:
settle(authorize), work,settle(capture)orsettle(void), response. Asynchronous and stateful: authorize, work, commitpaymentInfoto durable storage, respond, then capture, void or refund out of band. - Authorization — no hold at all.
verify, work,settle(charge), response, withrefundavailable later.
The client still signs exactly once. Whether that signature becomes an authorize or a charge follows from the flow, not from a second decision. And the later lifecycle calls are ordinary POST /settle requests with a payload.type of "capture", "void" or "refund" — the spec deliberately did not add a facilitator endpoint.
The interesting part is the authentication of those later calls. When we audited auth-capture in its v1.0 form, nothing bound the resource server's identity into the payment: a facilitator-relayed capture could not be proven to be the server's. v1.1 fixes that on EVM by hashing a non-zero extra.receiverAuthorizer — with an optional policy and a client-supplied saltNonce — into PaymentInfo.salt. A collected payment cannot be re-pointed at a different authorizer after the fact.
The spec also names the trust model explicitly, through extra.operatorType:
// delegated (default) — operator is an address the facilitator controls.
// With a non-zero receiverAuthorizer the facilitator relays collect AND
// lifecycle, gated by an EIP-712 authorizer signature that is NOT checked
// onchain. The server trusts the facilitator to submit what was signed.
// custom — operator is an untrusted contract with permissionless
// authorize/charge wrappers. The facilitator relays only the collect call;
// capture/void/refund go through the operator's own ABI, out of band.
// policy (reserved) — wire fields specified now so a later canonical
// operator can enforce the receiverAuthorizer check onchain.
Reading that third entry is worth the time. The spec is admitting that the default mode has an unenforced trust assumption, and reserving the wire format to close it later rather than pretending it is closed now. Facilitators advertise which operators they admit on /supported, and relaying into a custom operator requires gas caps and outcome checks — escrow events, paymentState, token movements — not just a successful top-level call.
receiverAuthorizer and policy are both omitted, which leaves the salt unbound. The moment you want the binding, you are on the v1.1 wire format with saltNonce, and the client's default signatures now target v1.1 escrow and collector addresses. Pinning v1.0 requires an explicit extra.authCaptureEscrow.
2. settlement_pending stopped being the caller's problem
Last week's roundup covered the arrival of settlement_pending: a non-terminal outcome for a settlement that was broadcast but whose receipt could not be retrieved. Naming the state was the easy half. PR #3214, merged on 25 August across 94 files and 11,276 added lines, did the hard half.
It introduces a PendingSettlementStore interface in Go, TypeScript and Python, keyed by a deterministic per-payload identifier — the EIP-3009 or Permit2 signature on EVM, the message hash on SVM. The store is written only on the broadcast-success-plus-confirm-failure path, checked before any new broadcast, and cleared on both terminal success and terminal failure. The default implementation is in-memory with a five-minute TTL and lazy pruning.
The resource server then retries a settlement_pending failure exactly once, with the identical payload, no backoff and no mutation. On that retry, the mechanism finds the stored transaction hash and reconciles against the transaction that already exists instead of verifying and broadcasting a second one. Any other outcome short-circuits after the first call.
Two details make this more than a retry loop. First, the store is an interface rather than a concrete type, because a multi-instance facilitator with no session affinity needs a shared backend — Redis is the named example — and the in-memory default would silently fail there. Second, coverage now spans EVM exact (both EIP-3009 and Permit2), EVM upto, EVM batch-settlement, SVM exact and SVM upto; the documentation update extends the guarantee from EVM-only to both families.
The PR documents its own gap, which is the part we would want in every protocol change: the batch-settlement reconcilePendingDeposit cache-hit path skips a balance-confirmation check that the cache-miss path performs, because it lacks the pre-broadcast channel-state snapshot. Stated inline, in all three languages.
3. exact learned to settle before it serves
PR #3240, merged on 25 August across 98 files, gives the exact scheme a second payment flow: upfront.
By default exact uses the authorization flow — verify before the handler runs, settle after. With upfront, settlement happens before the handler runs at all. The facilitator's /settle endpoint both validates and commits, and /verify is never called. The client signs the same payload either way; only the server-side ordering changes.
app.use(paymentMiddleware({
"GET /weather": {
accepts: [{
scheme: "exact",
price: "$0.001",
network: "eip155:84532",
payTo: evmAddress,
extra: { paymentFlow: "upfront" }, // settle, then run the handler
}],
},
}, resourceServer));
The motivating case in the documentation is precise: a long-running handler on Solana, where the signed transaction's blockhash may expire before the handler finishes. Verify-then-work-then-settle is a race against block time. Settling first removes the race and replaces it with a different one — the buyer has paid for work that has not happened yet.
The defaults reflect that trade honestly. authorization remains the default, clients prefer it when both are offered, servers opt in per route, and the server signals the resolved flow back through extra.paymentFlow in the 402 response. The upto and batch-settlement schemes still declare authorization only.
Put the three changes side by side and the shape is clear. upfront moves settlement earlier. Escrow moves finalisation later. settlement_pending handles the case where it lands somewhere in between. A single-round-trip payment protocol has grown three different answers to "when does the money move".
4. MCP published a roadmap and chartered a transport group
On 22 August the MCP maintainers replaced the March roadmap with a new one, authored by lead maintainers David Soria Parra and Den Delimarsky. It names five priority areas: agentic messaging primitives, HTTP-native transport unification and hardening, agent identity and enterprise-ready security, improved primitives, and improved SDK developer experience.
The concrete items matter more than the headings. Server-initiated events — webhooks and channels — so clients stop polling for results. Maturing the Tasks extension (SEP-2663) until it can move into the specification proper. Extending Streamable HTTP down to local servers over stdio, so the stateless core shipped in 2026-07-28 applies everywhere rather than only remotely. Finalising DPoP, implementing Workload Identity Federation, and continuing engagement with the IETF OAuth and WIMSE working groups. Progressive discovery for tool catalogs, so a client no longer has to load an entire tool surface before a user can act.
Two governance notes are easy to miss. Enterprise-Managed Authorization is now marked stable. And SEPs falling inside these five areas get expedited review — which turns the roadmap from a statement of intent into a routing table for contributor effort. Release dates were intentionally left out.
Four days later, on 26 August, the Transports Working Group charter merged, led by Kurtis Van Gent. In scope: transport bindings, connection lifecycle, multiplexing, delivery guarantees, stateless operation, and transport security (TLS, mTLS, Origin validation) jointly with the Security Interest Group. Out of scope, explicitly: application-layer behaviour, authorization mechanics, SDK internals, and ownership of the conformance suite. Additive spec changes need WG consensus plus Core Maintainer approval; breaking changes need wider review.
5. Also shipped
Sei joined the EVM default assets table on 24 August via PR #3227: native USDC on mainnet (eip155:1329) and testnet (eip155:1328), both verified onchain as six-decimal USDC version 2 with EIP-3009 authorization state and matching EIP-712 domain separators. The same PR corrected Python's legacy Sei Testnet chain ID from 713715 to 1328 — a wrong chain ID in a domain separator is a signature that verifies nowhere, which is exactly the failure class we walked through in the default assets audit.
Alongside it, PR #3241 removed duplicate network maps from the Go and Python SDKs to align their default-asset declaration with TypeScript: 48 files, 257 lines added and 1,163 removed. Net deletion is the correct direction for a table that three languages have to agree on. The docs table gained Ethereum mainnet and Avalanche C-Chain rows the same day, and Python received the payment-flow port on 24 August. Fireblocks was added to the published facilitator list on 20 August, described as open-source and hosted, with settlement from a Fireblocks vault and private keys that never leave it.
What it means for LLM4Agents
The three x402 changes are not equally relevant to an inference gateway, and it is worth being precise about which is which.
settlement_pending auto-recovery is the one we inherit for free and should adopt immediately. Our billing path reserves, proxies and settles; a broadcast whose receipt we cannot read is the exact failure that turns one inference call into two charges. The client-side retry is now in the SDK, but the PendingSettlementStore default is in-memory, and any gateway running more than one replica needs the shared implementation. That is a deployment decision, not a code one, and getting it wrong reintroduces the bug the PR was written to remove.
The upfront flow is the one we should mostly decline. Settling before the handler runs is right when block time is the risk; for inference, the price is not known until the tokens are counted, which is why the upto scheme exists and why upto still declares authorization only. Where upfront does fit is fixed-price ancillary endpoints — a tool call, a lookup, a cached completion — served under exact.
auth-capture v1.1 is the one that changes what we can offer. An authorize-then-capture lifecycle with a bound authorizer is how a gateway sells a session rather than a request: hold a ceiling when the agent opens a conversation, capture the actual spend when it closes, void the difference. The walk-up versus account decision gets a third option — a walk-up agent that does not need an account but does need more than one call. The caveat is the delegated operator's unenforced authorizer signature: for now, running that mode means trusting a facilitator to submit exactly what we signed.
Staying on the frontier
Four things, in order.
First, replace the in-memory pending-settlement store before enabling anything else. A shared, network-backed PendingSettlementStore is a prerequisite for horizontal scaling of the settlement path, and it is a small change made expensive by discovering it in production.
Second, prototype auth-capture v1.1 escrow for session-scoped inference. Authorize a per-session ceiling, capture actual token spend at close, void the remainder. Use the delegated operator with an explicit receiverAuthorizer so the lifecycle is bound to us, and track the reserved policy operator type — when a canonical operator enforces the authorizer check onchain, that is the day the trust assumption disappears and we should migrate the same week.
Third, adopt upfront selectively and say so in the 402. Fixed-price endpoints only, per route, with authorization left as the default for anything metered. The flow is advertised in extra.paymentFlow, so buyers can see the ordering before they sign.
Fourth, follow MCP's server-initiated events work now, not when it ships. Webhooks and channels plus a matured Tasks extension is the difference between an agent that polls our gateway for a long-running job and one that gets called back. Our MCP server currently assumes the polling model. SEPs in the roadmap's five areas get expedited review, which means this lands sooner than the absence of published dates suggests.
Pay per inference, in stablecoins, over an OpenAI-compatible API
x402 and EIP-3009 settlement, model routing and fallback, no subscription.
Register an agent