feat(ucp): negotiate payment method on checkout completion, escalate to browser handoff when none is supported - #152
Open
Lukas Rump (lukasrump) wants to merge 1 commit into
Conversation
Lukas Rump (lukasrump)
force-pushed
the
feat/ucp-payment-method-negotiation
branch
from
July 29, 2026 12:52
8ff49e4 to
e0596ed
Compare
Place an order on completeCheckout only when the client committed a payment handler the shop can settle (registered in the SDK PaymentHandlerRegistry). When the per-channel policy requireCommittedPaymentMethod is enabled and no supported handler was committed, return the checkout as requires_escalation with a continue_url and place no order — the UCP-standard fallback that lets a human finish in a browser. Off by default: completion proceeds unchanged (UCP treats the payment object as optional), so this is opt-in per channel and non-breaking.
Lukas Rump (lukasrump)
force-pushed
the
feat/ucp-payment-method-negotiation
branch
from
July 29, 2026 13:08
e0596ed to
a65bb2b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Today the checkout completer places an order regardless of whether the client can
actually pay through any handler the shop advertises. For x402 (order-first,
settle-after) that's by design, but it means a client that supports none of the
advertised
payment_handlerseither ends up with a placed, never-payable order orno path forward.
This adds a deterministic, opt-in payment-method negotiation:
CheckoutUpdateRequest.payment(PaymentInstrument).PaymentHandlerRegistry, the order is placed as today.returned as
requires_escalationwith acontinue_urland no order is placed —the UCP-standard fallback that lets a human finish in a browser.
It's driven by what the client agrees to pay with, not by what the shop offers, so
the shop never silently places an order (e.g. an unpaid invoice order) against a method
the agent didn't choose.
Opt-in / non-breaking
Gated behind a per-channel policy
requireCommittedPaymentMethod(default off):payment method (spec-conformant: the UCP
paymentobject is optional).So this changes nothing unless a merchant opts in — suitable for agent-only channels
that must not accumulate phantom unpaid orders. The flag is read via
SystemConfigService(
SwagAgenticCommerce.config.requireCommittedPaymentMethod); an admin toggle (config.xml)is an easy follow-up.
Spec alignment
PaymentInstrumenton update andpayment_handlersadvertisement are standard UCP.requires_escalation+continue_urlis the spec's prescribed fallback for acapability/negotiation failure.
Scope
Ucp/Checkout/CheckoutSessionStore.php,CheckoutSessionManager.php— persist/read the committed handler id.Ucp/Adapter/ShopwareCheckoutAdapter.php— capture the commitment on update; policy-gated escalation on complete.docs/payment-method-negotiation.md.continue_urlcan point at any merchant checkout; a signed cart-adopting handoff route is deployment-specific and intentionally not included here.Coordination note
feat/ucp-ap2-mandatesreworks completion to aCheckoutCompleteRequest/verifiedCheckoutAPI. This targetsmain; once that branch lands, the escalationgate should move into the request-based flow. Happy to rebase/adapt.
Testing
Unit test added for the escalation path (policy on + no supported handler committed ⇒
requires_escalation, completer never invoked → no order). Please run PHPStan/PHPUnit inCI — the branch was authored without a local PHP toolchain.