Past "Add to Cart": UCP's Payment Layer Learns 3DS Challenges and Negotiated Terms
Most of the noise in agentic commerce is about discovery: can an agent find a product, read a price, add it to a cart. That was never the hard part. The hard part is everything that happens after the buy button — the step-up authentication challenge from the issuer, the "pay in four" option the merchant wants to offer, the deferred obligation that has to survive to the receipt. That's where real checkouts get messy, and it's where a protocol either grows teeth or stays a demo.
In the last week UCP shipped two of those hard parts, both merged: a standard shape for payment authentication (#458), and negotiated payment terms as a first-class checkout selection (#603 → #692). A third change (#689) hardened how fulfillment destinations are typed. Taken together, they're the clearest signal yet that the protocol is maturing from "can an agent shop" to "can an agent actually pay."
The authentication wall
Ask anyone who has tried to build a checkout agent where it breaks, and you'll hear the same answer: the moment the issuer wants strong customer authentication. A 3-D Secure challenge or a device-data-collection step appears, an agent that only knows how to fill fields and click Pay stalls, and the flow falls back to a human — if it recovers at all.
#458 introduces dev.ucp.shopping.payment_authentication, a Checkout extension that gives that moment a standard shape. It defines two browser-surface Action types:
dev.ucp.payment.device_data_collectiondev.ucp.payment.three_ds_challenge
The design choice worth noticing is what it doesn't try to do. EMVCo already defines the interaction between the issuer's authentication server, the card network's directory server, and the merchant's 3DS provider. UCP doesn't restate any of that. Instead it standardizes the thin abstraction layer that businesses and payment providers actually have to expose to an agent — a simple resolve-or-reject signal pattern that works the same whether the challenge renders on a business's own surface or a platform's. The heavy machinery stays where it lives; the agent gets a predictable contract.
This rides on the Actions primitive that merged in July (#582) — the response-only shape that lets an extension hand an agent outstanding work at checkout. Payment authentication is the first heavyweight thing built on it, and it's a good stress test of that primitive: authentication is exactly the kind of Action where who is behind it matters, which is why the authority-binding question we wrote about when Actions landed isn't academic. The primitive was the foundation; this is the load it was built to carry.
Payment terms become a negotiation
The second change is bigger than it looks. #603 and then #692 make a payment term a negotiated selection rather than a fixed property of an instrument.
The mechanics are clean. A Business offers a list of terms — pay in full now, pay in four, net-30, a deposit-plus-schedule — the Buyer picks one, and the Business reprices around the choice. A new first-class field, payment.selected_term_id, carries that decision. And the direction of dependency flips in a way that matters: the selected term now determines the price, the disclosure duties, and which payment instruments are eligible — eligibility follows from the term, rather than the term hanging off the instrument. (The old instruments[].term_refs link is superseded and removed.) That eligibility rule sits on top of a question the spec settled separately this summer: how does an authenticated shopper's own instruments — a saved card, a wallet balance, store credit — surface at all? The answer that landed (#585) was that they need no new field; a business populates them into the existing payment.instruments[] on an identity-linked session. So the two halves compose cleanly: payment.instruments[] is what a buyer has available, and #692 decides which of those are eligible under the chosen term — together, what this shopper can actually pay with, right now.
The design borrows a shape UCP already had rather than inventing a new one. Fulfillment already models "a list of priced options with exactly one selection" — options[] plus selected_option_id. Payment terms copy it: terms[] plus selected_term_id, a per-schedule amount, response-only list direction, absolute timestamps. (A follow-up refinement, #712, simplified further still — a scalar amount per schedule rather than a full totals breakdown — and made the whole extension optional: a checkout with no term means payment is due in full at completion, exactly as core Checkout already works, so the negotiation costs an ordinary checkout nothing.) Reusing a proven shape instead of minting a second one for the same problem is the kind of restraint that keeps a protocol legible as it grows.
Two details show the authors thinking past the happy path:
- The obligation survives to the Order. A
payment.accepted_termnode carries the chosen term — with its schedules and totals — onto the completed Order. The reasoning is exactly right: a checkout-only disclosure evaporates at completion, which is precisely when a deferred obligation starts to matter. A buyer who owes a balance at a later date now has a protocol-level record of it, not just a screen they saw once. The accepted term is the agreement, fixed at creation; anything that happens afterward (a refund, an exchange) is recorded separately in signedadjustments[]. - Silent repricing is a reportable event. If a selected term stops resolving — or the Business changes it to resolve a conflict elsewhere in the checkout — that must surface as a
payment_term_changedwarning, so an agent detects it from an explicit code instead of by diffing responses and hoping to notice.
For anyone building B2B or higher-ticket agentic flows, this is the unlock. "Agent buys thing" is table stakes; "agent negotiates net-30 with a documented schedule that lands on the order" is commerce. It also narrows one of the most-cited gaps in the B2B debate: net-30/60/90 has long been the canonical "UCP is card-at-checkout, so it can't really do B2B" example — and a term with a due-date thirty days out is precisely that. The procurement scaffolding around it (approvals, POs, cost centers) is still missing; the payment primitive underneath it no longer is.
A quieter, careful fix
Alongside the headline work, #689 tidied how fulfillment destinations are typed — moving the discriminator up from each destination object to the fulfillment method level, so a method's type selects the shape of its whole subtree (a shipping method carries shipping destinations; a pickup method carries business-location destinations, response-only).
It's plumbing, but the way it was done is the tell. The change is marked breaking, yet it was deliberately shaped to keep every request wire format platforms send today valid — the migration cost falls on the additive, response side rather than invalidating deployed integrations. A standard that hardens its schema while protecting the integrations already in the field is a standard being run by people who expect it to be depended on.
Why we're watching the payment layer specifically
Discovery-readiness and transaction-readiness are two different things, and the gap between them is exactly what a one-time "is it UCP-ready?" badge misses. A store can advertise a manifest and still stall the moment a 3DS challenge appears or a term needs repricing. That's the whole premise of measuring two vantages: what a store declares it supports, and what actually resolves when an agent runs the flow.
Payment authentication and negotiated terms are new surface area on the second vantage — new capabilities that will show up unevenly across the ecosystem, work on some stacks before others, and drift. As an independent reference for UCP, that unevenness is the thing worth tracking: not who announced support, but where declared capability and observed behavior line up, and where they don't.
The protocol just took on two of the hardest jobs in a checkout. The interesting question now isn't whether the spec can express them — it can — but which of the stores flying UCP colors can actually see them through. That's the part you have to observe, not assert.
About UCP Checker
UCP Checker is the independent validation and observability layer for the Universal Commerce Protocol. We crawl, validate and grade every public UCP manifest we can find, run the merchant directory, the UCP Score, live adoption stats, the payment-handler index and the authority-bound vendor map, and track the spec as it evolves so you don't have to — measured from two vantages (what a store declares, and what actually happens when an agent transacts), the same way for everyone, without picking winners.
Sources
- #458 — Add Payment Authentication Actions
- #603 — Add Payment Terms with Simple Schedules
- #692 — negotiate payment terms as a checkout selection
- #712 — refine payment terms: optional terms + scalar amounts (merged)
- #689 — fix!: discriminate destinations at the method level
- #582 — the extension-defined Actions primitive
- #585 — clarify business-populated response values for identity-linked sessions (merged)
- Related coverage: the Actions primitive · UCP payment extensions go global · UCP for B2B
Check your domain's UCP status
See if your storefront is ready for agentic commerce in seconds.
Get the agentic commerce digest every Monday
Real adoption data, ecosystem trends, new spec versions, and the stores that broke or recovered this week. Read by founders and engineers building the next generation of commerce.

