x402 for Agentic E-commerce with Partial/Full Refund + Cancelation, and Returns
Abstract
x402 is an open standard for internet-native payments: a resource server responds 402 Payment Required, the client resubmits with a signed payment payload, and a facilitator verifies and settles it. Its most widely deployed scheme, exact, moves one authorized amount for one resource, once, and by the specification's own account has no built-in mechanism for returning funds. A second scheme, auth-capture, does support a refund, but as a scalar amount on one payment, gated by whichever facilitator or contract holds a capture-authorizer role, inside a fixed time window. Neither scheme, nor any other in the spec, defines a multi-item cart, a stateful checkout session, or an identity bound to the payment distinct from the signing wallet. This paper specifies x402 Direct, three primitives layered on top of x402's settlement leg rather than inside it: a signed checkout session that prices a real multi-line cart before any money moves, an agent-facing initiation route that expresses a partial refund, a damaged-goods return, and a full-order cancellation as one primitive with different inputs, and a non-custodial reverse settlement signed by the merchant's own wallet. The full loop, checkout through cancellation, is proven end to end on Base mainnet against a live commerce backend with real USDC, and every claim resolves to a transaction hash or a signature independently verifiable against a published key. The specification anticipated the need for a reverse leg: an auth-capture scheme was merged on 2026-05-13, and its reference TypeScript package shipped a client on 2026-05-29. That package states, as of this writing, that it "currently ships the client only" and that "server and facilitator support follow in a later change." The loop documented here settles real value on Base mainnet today, on the exact rail, without escrow infrastructure and without any party but the merchant able to sign a refund.
What x402 solves, precisely
The x402 flow is short by design. A client requests a resource; the server returns 402 with the terms it accepts; the client signs a payment payload against one of those terms and resubmits; a facilitator verifies the payload and settles it on-chain; the server serves the resource. Four schemes govern how settlement itself behaves: exact transfers the stated amount immediately. upto transfers up to a client-authorized maximum, settled for actual usage. batch-settlement accepts a commitment now and settles it later, in bulk, through a channel, voucher store, or billing cycle, built for volume where per-request on-chain settlement does not make sense. auth-capture holds funds in escrow or sends them direct, with a capture-authorizer able to void, capture, or refund inside a deadline.
Every one of the four is a payment scheme: it governs how value moves for a single authorized amount. None defines a cart, an authorization spanning more than one priced line. None defines a checkout session, a stateful object that survives across a quote, a line-item selection, and a settlement. None binds an identity to the request beyond the wallet whose signature the scheme verifies. That is not a gap in the engineering; it is the correct scope for a payment protocol, the same way a card network's authorization message is not supposed to know what is in a shopping cart or who is buying, a merchant's own checkout stack sits on top of the rail for that.
Agent commerce needs that stack too, and it needs the identity to mean something specific: a KYA-equivalent credential the merchant's own server can verify, not just recover a wallet address from a signature.
Three primitives, layered on the settlement leg
x402 Direct adds three things above x402's settlement leg. None require a change to the x402 spec; each is a layer a resource server and its client agree to speak before the 402 challenge fires.
- 1. Checkout sessiona stateful object, created and completed under RFC 9421 HTTP Message Signatures, that prices an arbitrary number of line items from a live commerce backend (goods, shipping, and jurisdiction-correct tax) before advertising the one
exact-scheme payment requirement the client ultimately signs. The cart is negotiated above x402; the money still moves through it, once, for the summed total. - 2. Agent-facing refund and cancellation initiationone route, signed the same way the checkout was, that a buyer's agent calls to open a ticket against a specific, already-settled order. An optional line-item selection makes it a partial refund; omitting the selection makes it a full-order cancellation; the reason is a string the agent supplies and the merchant reviews, so the same primitive covers a pre-shipping change of mind and a post-delivery damage claim without a separate code path for either.
- 3. Non-custodial reverse settlementthe merchant's own wallet, the same account that received the original payment, signs the ERC-3009 send-back client-side. The protocol layer verifies the signature, checks it against the order it claims to settle, and relays it through a facilitator. It never holds a key that could sign one.

exact scheme, does not compete with auth-capture, and does not reimplement the checkout-session or agent-identity concepts that the Universal Commerce Protocol (UCP) already specifies. It is the specific arrangement of UCP checkout sessions, a KYA-equivalent identity credential, and a merchant-signed reverse leg, composed to sit above the exact scheme, the one scheme in the spec that has no reverse leg of its own to conflict with.
The technical specification
Every request below is drawn from the real, on-chain-settled run in the validation report below; the shapes are exactly what shipped, not an illustrative simplification.
- Create.
POST /ucp/v1/checkout-sessions, RFC 9421 signed. Body: a line-item array (product_id,quantity) and a fulfillment destination. Response: a session id, statusready_for_complete, and apayment_handlersobject naming every rail the site has configured, the x402 handler carrying the server-pricedpay_to,amount_atomic, network, and EIP-712 domain the client must sign against. The session advertises every rail it has configured and privileges none; a Boson-escrow-only site and an x402-only site both create successfully. - Complete.
POST /ucp/v1/checkout-sessions/{id}/complete, RFC 9421 signed, carrying the buyer's ERC-3009TransferWithAuthorizationfor the exact amount and domain the create response advertised. Settlement moves the funds and creates the order in the merchant's own commerce backend, buyer wallet stamped on it, in the same call. - Refund or cancel, initiate.
POST /ucp/v1/checkout-sessions/refund, RFC 9421 signed, body{order_id, reason, refund_line_items?}. Authorization is bound to the order's real site id server-side, never to the caller's self-asserted identity, so a forged claim of ownership cannot open a ticket on an order it does not own. Moves no money; opens a ticket the merchant can review. - Refund or cancel, approve. The merchant's own client signs an ERC-3009 send-back from its own
pay_toto the order's stamped buyer address, for an amount the server derives from the merchant's own commerce order, never from the agent's request. The protocol layer checks signer equalspay_to, destination equals the stamped buyer, and amount equals the derived total, before relaying it to a facilitator.
Where this sits relative to what already exists
auth-capture is a payment-processor primitive: escrow, timers, a single authorizer role, useful for buyer protection on a payment that has no commerce system behind it. x402 Direct is a commerce-system primitive: it exists because there is a real order, a real merchant backend, and a real reason a human is reviewing. A site could use both, auth-capture for the payment guarantee, x402 Direct for the agent-facing request and the itemized reversal into its own books. The practical difference today is availability: a merchant who wants to give money back on x402 right now cannot wait for escrow settlement to land, and does not have to.Security model
- Non-custodial by construction, not by policy. The only two keys that ever sign a money leg are the buyer's, at checkout, and the merchant's own, at refund. The protocol layer verifies signatures; it produces none.
- Ownership is bound server-side. A refund ticket is opened against the site the settled order actually belongs to, resolved from the order record, never from a claim the caller's request makes about itself.
- The amount is never agent-set. A line-item selection is advisory input, validated against what was actually ordered; the number that gets signed is read from the merchant's own commerce order at approval time.
- A shared ledger caps every refund path together. A partial refund, a second partial refund, and a full cancellation on the same order are checked against one running total, so no combination of agent-initiated requests can exceed what was captured.
- Replay-proof. Every ERC-3009 authorization carries a single-use nonce consumed on-chain; a facilitator independently re-verifies a signature before broadcasting it.
- Reviewed adversarially before shipping. The merchant-signed reverse-settlement path was reviewed across independent attack lenses before its mainnet run, each finding checked by independent review passes; the one real functional gap found (a dead end for a merchant with no managed signer configured) was fixed before merge, not disclosed as a residual risk.
Why this belongs in the open, not in one company's stack
x402 Direct is deliberately not a fork, a competing payment scheme, or a reason to leave the spec. It is evidence for a specific, narrow claim: that exact plus a checkout-session layer plus an agent-facing initiation route plus a non-custodial reverse leg is enough to run real commerce, cart through cancellation, without a merchant ever handing custody of a refund key to anyone. That claim is falsifiable by exactly the same tools that verify the rest of x402: a transaction hash, a signature, a published key.
The open question worth the Foundation's attention is narrower than a whole new scheme: whether an identity credential distinct from the signing wallet, and a line-item-aware refund initiation bound to a real commerce order, belong as a documented extension pattern above exact, the way auth-capture documents a different, escrow-based answer to a related but distinct problem. This paper and the validation report it precedes are offered as the worked example.
On precedence, stated carefully because it is checkable. We are not claiming to have invented refunds on x402;
the specification's own auth-capture scheme describes an escrow-based answer, and it was
merged before this work was proven. What we can document is narrower and, we think, more useful: as of 2026-07-23,
the reference implementation of that scheme ships a client with server and facilitator support explicitly deferred,
and we are not aware of another agent-initiated refund and cancellation loop settling real value on x402 in
production. The loop in the validation report below did that on Base mainnet, non-custodially, on the
exact rail. If someone else got there first, the same standard of proof should settle it:
a transaction hash, a signature, a published key.
References
- x402 Foundation. x402 protocol specification.
github.com/x402-foundation/x402,specs/. - x402 Foundation. Scheme:
exact.specs/schemes/exact/. - x402 Foundation. Scheme:
auth-capture.specs/schemes/auth-capture/scheme_auth_capture.mdandscheme_auth_capture_evm.md. - x402 Foundation. Scheme:
upto.specs/schemes/upto/scheme_upto.md. - x402 Foundation. Scheme:
batch-settlement.specs/schemes/batch-settlement/scheme_batch_settlement.md. - Base. commerce-payments contract stack (AuthCaptureEscrow).
github.com/base/commerce-payments. - Universal Commerce Protocol. Specification and documentation.
github.com/Universal-Commerce-Protocol/ucp. - Circle. USDC EIP-3009
transferWithAuthorization/receiveWithAuthorization. - IETF. RFC 9421, HTTP Message Signatures.
- Facet, LLC. x402 Direct mainnet validation: UCP-signed checkout, merchant-approved refund, and agent-initiated cancellation on Base mainnet. Appended below.
x402 Direct mainnet validation
UCP-signed checkout, merchant-approved refund, and agent-initiated cancellation, settled on Base mainnet with real USDC. Every claim in the paper above is backed by a request, a signature, and a transaction below. Each is independently checkable against a public block explorer.
Setup: all public, all on-chain
Merchant: Pecan and Petal, a live WooCommerce store on the Facet Terminal at pecanandpetal.facet.llc. Rail: coin/usdc-base (x402-direct). Network: Base mainnet, chain 8453, real USDC at 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913. Merchant receiving wallet (the x402 pay_to): 0x0BE0574bD5Fbd20E6187e6f3B6A889791699CcC3, a plain externally owned account the merchant controls directly, not a Facet-operated key. Buyer wallet: 0xC0D344C8D10F5f9C64Cb96148FcF176BA170D21E.
transferWithAuthorization on-chain and pays the gas, on the purchase leg and on every refund leg below.What base x402 is, and what sits on top of it
x402 is an open, HTTP-native payment protocol: a server responds 402 Payment Required with the terms of a single resource, the client resubmits with a signed X-PAYMENT header carrying an ERC-3009 authorization, and a facilitator verifies and settles it on-chain. That primitive is exactly what it needs to be: one payment, for one resource, at request time.
No scheme in the spec (exact, upto, batch-settlement, or auth-capture) defines a cart, more than one line item under one authorization, or a checkout session, a stateful negotiation between quote and settlement. None binds an agent identity distinct from the wallet that signs.
The rail this report settles on is exact, and by the spec's own account it "has no built-in mechanism for returning funds" once settled. A separate scheme, auth-capture, does support a refund, but as a scalar amount on one payment, exercised by whichever facilitator or escrow contract holds the captureAuthorizer role, inside a fixed capture and refund deadline. It has no concept of a line-item selection against a real commerce order, and no concept of an agent distinct from the signer. Its reference implementation also ships the client only as of this writing, with server and facilitator support deferred to a later change, so it offers no settlement path today.
Every leg below is x402 settlement underneath. What sits on top, and what this report proves end to end, is four additions: a real multi-item cart negotiated through a signed checkout session (UCP checkout-sessions); an agent identity bound to a specific site by that same signature, not a forgeable claim; one agent-facing initiation route that expresses a partial refund, a damaged-goods return, and a full-order cancellation as the same primitive with different inputs; and a reverse settlement signed by the merchant's own wallet that Facet only relays, never holds.
The checkout: a real 2-item cart, UCP-signed, real USDC
An autonomous agent creates a checkout session for two SKUs (a $3 card and a $15 flower arrangement), the Terminal prices the landed total from a live quote (goods, shipping, and Texas sales tax), and the agent completes it with the buyer's own payment authorization. The CREATE and COMPLETE requests are each independently signed by Facet's platform key under RFC 9421; the money authorization is the buyer's own ERC-3009 signature, never Facet's.
- CartHCF-CARD x 1 ($3.00) + HCF-BDAY x 1 ($15.00) = $18.00 goods + $9.00 delivery + $1.49 Texas sales tax = $28.49 landed, advertised by the checkout session and matched exactly by the on-chain charge.
- Checkout session
941f29a3-712f-4055-b60a-31594cd2251b, statusready_for_complete, advertised pay_to0x0BE0574bD5Fbd20E6187e6f3B6A889791699CcC3, advertised amount28490000atomic USDC. - Settletx
0x20d5e6084ea6c3798057d2139dd392fe5aaa01462f48e843dbc197cb4b763d6c, block 48999141, $28.49 USDC buyer to merchant, status success. Creates a real WooCommerce order (order 135), buyer wallet stamped on the order for the refund legs below. - Buyer identitya single-use Facet KYA (ES256 JWT, type kya+jwt, issuer
issuer.facet.llc), fresh per call, expired minutes after issuance.

Partial refund by line selection: the card, pre-shipping
The agent requests a refund of exactly one line (product HCF-CARD, quantity 1) over the same RFC 9421-signed agent-facing route the checkout used. The Terminal derives the taxed line amount from the merchant's own order, the merchant reviews and approves, and the merchant's own wallet, the same account that received the purchase, signs the send-back. Facet relays a signature it never held the key to.
- Ticket
b7c7c94a-4d59-45ea-ba17-0ab7775f1764, reason "buyer requested a partial refund (card line)". - Send-backtx
0x66e658fda738384f7f558e7428241e5e91457fb95e8a2eca0bc6f995d8b7efee, block 49024328, $3.25 USDC (the $3.00 line plus its $0.25 tax) merchant to buyer, status success. - Left capturedthe flower line and the $9.00 delivery fee.


Post-delivery damaged return: the arrangement, after shipping
The identical route and the identical merchant wallet handle a second, independent reason on the same order: the flower arrangement arrived damaged. Nothing about the mechanism changes between a pre-shipping change of mind and a post-delivery damage claim. The reason is a string the agent supplies; the money path is the same primitive.
- Ticket
327c3094-56ba-4b3c-a2ad-b2a516ed38b6, reason "delivered damaged: arrangement arrived wilted". - Send-backtx
0x63b0660bfee828d78198b0c9dad31634b6329cbdecdc327278ce59df65a3f3c1, block 49026760, $16.24 USDC (the $15.00 line plus its $1.24 tax) merchant to buyer, status success. - Signature captureissued over the same RFC 9421-signed route, from the same platform key, as the other two requests in this report. The raw request bytes for this specific call were not retained in this run; the ticket record and the on-chain settlement above are independently verifiable without them.


Agent-initiated cancellation: a full order, before fulfillment
A cancellation is the same route with the line selection omitted rather than populated: no line items at all, so the Terminal derives the entire captured total, shipping included, rather than one line. This is a second, freshly settled order, cancelled by the buyer's agent before fulfillment and approved by the same merchant wallet.
- OrderWoo order 138, a single-item purchase (HCF-CARD x 1, $3.00 goods + $9.00 delivery + $0.25 tax = $12.25 landed), settled the same way as section 02.
- Ticket
180b65b3-2808-4489-8cf5-f44932596b1a, reason "buyer cancelled the order before fulfillment (full refund)", no line selection supplied. - Send-backtx
0x0370b28b629336725be8f72f7657ae3955262365442be57127fd06408e6731e9, block 49027308, $12.25 USDC, the full captured total including delivery, merchant to buyer, status success.


The signature inventory: nothing is unsigned
Every leg below carries a real signature, quoted verbatim from the actual request or transaction. The RFC 9421 signatures verify against Facet's published platform key for this run (P-256, ES256), reproduced at the end of this section; the money-leg signatures are embedded in the on-chain transactions and independently verifiable on BaseScan.
| Leg | Order | Platform signature, RFC 9421, ES256 | Money authorization, secp256k1, on-chain |
|---|---|---|---|
| Checkout CREATE | 135 | created=1784787625; keyid="facet-ucp-platform-validation-2026"sig1=:8UBB3txg9L/fK+nDMzgWqp6Y5zz5kEq+NPAcpyaP0id+awGNtt+MyEkqfEL5Si2pLluYanm+MgeEbV9JLxOhIQ==: | none, cart pricing only, no money leg |
| Checkout COMPLETE | 135 | created=1784787627; keyid="facet-ucp-platform-validation-2026"sig1=:iQaRx1ekcJM/iaHS7iNPTePlyZ/0jcGG2d86pTe46me+1ebD+LymPhgzSlgXolx4l8cR6qhkipqDmuQBCOPkXw==: | buyer ERC-3009: 0x2097f259bf4be44a404c695c180fce4b80b815c0c9603e29dc34d54510f9e8084c5be9726f22874579cd6af411313bbca55281cdd9c7f6d947909e9dadbad6381b, settled tx 0x20d5e6084ea6c3798057d2139dd392fe5aaa01462f48e843dbc197cb4b763d6c |
| Refund request, card | 135 | created=1784818161; keyid="facet-ucp-platform-validation-2026"sig1=:8mgHzh0zM3z30KmAnNUdeMR4ZgCzNIR1EKK/UZ8mlr/fLMyl6OLMhv9dNxsBVOQNcvNisOAwYfJ7ExCZI5DWsg==: | merchant ERC-3009 send-back, tx 0x66e658fda738384f7f558e7428241e5e91457fb95e8a2eca0bc6f995d8b7efee |
| Refund request, flowers | 135 | same route, same platform key as above (bytes not retained for this call) | merchant ERC-3009 send-back, tx 0x63b0660bfee828d78198b0c9dad31634b6329cbdecdc327278ce59df65a3f3c1 |
| Refund request, full cancel | 138 | created=1784843850; keyid="facet-ucp-platform-validation-2026"sig1=:oMccbYAGAsGcOXMhgGm6yBTuHjux+US6pDffVCzqh0NzTbgq2Fx2SB4o9sbtfterGPkhNdMou4uKCClO1/FYIg==: | merchant ERC-3009 send-back, tx 0x0370b28b629336725be8f72f7657ae3955262365442be57127fd06408e6731e9 |
keyid above names Facet's UCP platform request-signing key: the key Facet signs with when it calls a business as a platform. It is deliberately distinct from the business response-signing key each Facet Terminal advertises at its own /.well-known/ucp, because the two answer different questions (who sent this request, versus who answered it). Platform public key for this run, EC P-256: kid facet-ucp-platform-validation-2026, x=iiNBe3_n_wSECRyxyawkmO4ufk9Oscc58Ka4cK3vlLM, y=i68drm5xsC21PZ7_7zplfJKRPta6OsBGw8lu_XHbDKU. You do not have to take these coordinates from this page: resolve the keyid yourself against Facet's platform profile at facet.llc/ucp/platform.json, which publishes this key permanently so the signatures in this report stay verifiable after the signing key is rotated. Every ERC-3009 signature above recovers to its stated signer under standard ecrecover; every transaction hash resolves on basescan.org.Guarantees: why the agent controls no money
- The refund signer must equal the merchant's own pay_to. Checked before anything is signed, so a send-back can only ever move funds out of the wallet that received the original purchase. It cannot be pointed at a different wallet, and Facet holds no key that could sign one anyway.
- The destination is the order's stamped buyer wallet. Never a field in the agent's request. An agent can propose which line to refund; it cannot propose where the money goes.
- The amount is server-derived, never agent-set. The taxed total is read from the merchant's own commerce order at approval time. A partial selection is advisory input, validated against the ordered line items; the number that gets signed comes from the merchant's own books.
- A shared budget ledger caps every refund path together, per order. A card partial, a flowers partial, and a would-be third claim on the same order are all checked against one running total, so no combination of requests can ever exceed what was captured.
- The ERC-3009 nonce is single-use on-chain. A captured send-back signature cannot be replayed; the facilitator independently re-verifies the signature before broadcasting.
- Gasless on every leg. The buyer signs to buy, the merchant signs to refund, and a relayer broadcasts and pays gas both ways.
Summary and how to verify
Three independent money-return requests, one mechanism: a partial refund by line selection, a post-delivery damaged-goods return, and a full-order agent-initiated cancellation, each opened by the buyer's agent under an RFC 9421-signed request bound to the real site, each approved and signed by the merchant's own wallet, each settled gaslessly on Base mainnet with real USDC. To verify independently: look up each transaction hash above on basescan.org and confirm sender, recipient, and amount; recompute each RFC 9421 signature against the published platform key; confirm 0x0BE0574bD5Fbd20E6187e6f3B6A889791699CcC3 is a plain externally owned account (empty eth_getCode) and not a contract Facet or anyone else controls.