<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged ucp</title>
<link>https://coderlegion.com/tag/ucp</link>
<description>Powered by Question2Answer</description>
<item>
<title>The Stack Nobody Talks About: Why Travel Needs an Execution Runtime</title>
<link>https://coderlegion.com/21415/the-stack-nobody-talks-about-why-travel-needs-an-execution-runtime</link>
<description>&lt;p&gt;Google just published the UCP Lodging charter. Booking.com, Expedia, Hilton, Marriott, Amadeus, Trip.com. The largest players in travel have aligned around UCP as the open standard for lodging distribution.&lt;/p&gt;
&lt;p&gt;The industry just mapped the destination. The question nobody in that charter answered is who executes the transaction when the agent arrives there.&lt;/p&gt;
&lt;p&gt;The charter defines interoperability. It does not specify the execution runtime that carries an autonomous transaction from intent to confirmed booking. Those are different problems.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP enabled the Web.
OAuth enabled delegated identity.
MCP enables tool invocation.
UCP defines commerce interoperability.
UCP.travel enables autonomous travel execution.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That last line is not marketing. It is a technical claim about a missing layer. This article explains what the layer is, why it has to exist, and why none of the charter signatories have shipped it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-agents-can-do-today-vs-what-they-need-to-do&quot;&gt;What agents can do today vs what they need to do&lt;/h3&gt;
&lt;p&gt;An AI agent connected to a travel search tool can find flights. It can present options, explain fare conditions, and compare prices. That part works. The agent is an excellent research assistant.&lt;/p&gt;
&lt;p&gt;The problem is that research is not a booking. A booking requires:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A verified offer that has not expired&lt;/li&gt;
&lt;li&gt;A confirmed price that has not changed since search&lt;/li&gt;
&lt;li&gt;An authenticated identity on whose behalf the transaction occurs&lt;/li&gt;
&lt;li&gt;A cryptographic mandate proving that identity authorized this specific transaction&lt;/li&gt;
&lt;li&gt;A payment that clears without a human opening a browser&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every travel API on the market stops short of this list. They provide inventory access. They do not provide execution.&lt;/p&gt;
&lt;p&gt;An API exposes operations. An execution runtime owns the outcome.&lt;/p&gt;
&lt;p&gt;The gap between inventory access and confirmed booking is where every autonomous travel agent demo breaks. The offer expires while the agent is reasoning. The price changes between search and purchase. The payment step requires 3D Secure, which requires a human to complete a browser challenge. The booking comes back as a pending confirmation that the agent does not know how to handle.&lt;/p&gt;
&lt;p&gt;These are not edge cases. They happen on every booking in production.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-the-incumbents-cannot-close-this-gap&quot;&gt;Why the incumbents cannot close this gap&lt;/h3&gt;
&lt;p&gt;The global distribution systems were built when the assumed actor at every step was a trained human agent. The EDIFACT messaging protocol that still processes the majority of global airline transactions was designed in the 1980s. NDC modernized the data format but did not change the assumption: a human reviews the offer, a human approves the price, a human completes the payment.&lt;/p&gt;
&lt;p&gt;Layering an AI interface on top of a human-assumed architecture produces a better research tool, not an autonomous execution system. The agent can fill the form. It cannot own the transaction.&lt;/p&gt;
&lt;p&gt;The reason this has not been solved is not technical difficulty alone. It is that solving it requires rethinking the settlement chain, not just the interface. Who is responsible when an agent books at a price that changed between search and purchase? Who holds the mandate that authorizes autonomous payment? Who owns the audit trail when a dispute occurs?&lt;/p&gt;
&lt;p&gt;These are architecture questions. They require a purpose-built layer, not a plugin on top of an existing one.&lt;/p&gt;
&lt;p&gt;Signing a charter defines intent. It does not ship a runtime.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-an-execution-runtime-actually-does&quot;&gt;What an execution runtime actually does&lt;/h3&gt;
&lt;p&gt;An execution runtime is not another API. It is the trusted decision layer between an autonomous agent and supplier infrastructure. It verifies policy, identity, mandates, payment eligibility, offer validity, and booking state before any transaction commits.&lt;/p&gt;
&lt;p&gt;Every major shift in computing created a new execution layer. HTTP did not eliminate web servers. OAuth did not eliminate authorization systems. UCP will not eliminate execution runtimes. Someone still has to decide whether a transaction is allowed to commit.&lt;/p&gt;
&lt;p&gt;That execution layer is what &lt;a rel=&quot;nofollow&quot; href=&quot;https://ucp.travel&quot;&gt;UCP.travel&lt;/a&gt; implements.&lt;/p&gt;
&lt;p&gt;It sits between the AI agent and the travel inventory. The agent calls tools. The runtime handles everything the agent cannot handle on its own.&lt;/p&gt;
&lt;p&gt;Concretely, before any booking completes, the runtime verifies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The offer is still live and has not expired&lt;/li&gt;
&lt;li&gt;The price has not changed since the agent retrieved it; if it has, the delta surfaces before money moves&lt;/li&gt;
&lt;li&gt;The traveler's identity is authenticated via OAuth&lt;/li&gt;
&lt;li&gt;A signed mandate exists confirming this traveler authorized this class of transaction at this price&lt;/li&gt;
&lt;li&gt;The payment clears without requiring a browser challenge&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of these conditions fails, the booking does not proceed. The agent receives a structured error with an instruction for what to do next. No silent failures. No double charges on retry. No expired offer exceptions the agent cannot recover from.&lt;/p&gt;
&lt;p&gt;This is not a feature list. It is what makes the difference between a demo and a production system.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-stack&quot;&gt;The stack&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=6576059731585644531&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Each layer solves a problem the layer below it cannot. The LLM reasons but does not invoke. MCP invokes but does not transact. UCP defines how systems exchange commerce but does not enforce whether a specific transaction is allowed to commit. That is the execution layer.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;two-webs-two-models&quot;&gt;Two webs, two models&lt;/h3&gt;
&lt;p&gt;The web was built for human request-response. Autonomous commerce runs on a different model entirely.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=8948677720017053840&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The human web assumes a person at every decision point. The agent web assumes a runtime. Without a runtime that can enforce mandate, verify policy, and commit transactions, the agent web is just the human web with a chatbot in front of it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;this-has-been-demonstrated-in-production&quot;&gt;This has been demonstrated in production&lt;/h3&gt;
&lt;p&gt;On June 1, 2026, at 15:33 CET, a Gemini 2.5 Flash agent connected to the UCP.travel MCP endpoint, called two tools, and completed a confirmed flight booking in 8 seconds.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Turn 1: search_flights(origin: ZAG, destination: AMS, departure_date: 2026-06-02, max_connections: 0)
Turn 2: complete_checkout(offer_id: ..., checkout_id: ...)
Turn 3: confirmed — PNR returned
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The PNR was visible in the travel provider dashboard within seconds. No human touched the booking flow after the traveler's one-time setup.&lt;/p&gt;
&lt;p&gt;The &lt;a rel=&quot;nofollow&quot; href=&quot;https://ucp.travel&quot;&gt;UCP.travel&lt;/a&gt; manifest is public at &lt;code&gt;ucp.travel/.well-known/ucp&lt;/code&gt; and verified by &lt;a rel=&quot;nofollow&quot; href=&quot;https://ucpchecker.com/status/ucp.travel&quot;&gt;UCPChecker&lt;/a&gt;. It is currently the only verified implementation of &lt;code&gt;travel.ucp.mandate&lt;/code&gt; in the UCP ecosystem.&lt;/p&gt;
&lt;p&gt;As travel joins the UCP ecosystem, execution semantics such as offer validity, passenger identity, mandates, payment authorization, and supplier confirmation will need to be represented alongside the base protocol.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Love the Agentic AI workflow &amp;amp; distribution layer! Good stuff, keep it coming!&quot;&lt;br&gt;
— Fritz Oberhummer, Strategy Advisory for Product, Platform &amp;amp; AI, &lt;a rel=&quot;nofollow&quot; href=&quot;https://oberhummer.com&quot;&gt;oberhummer.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-protocol-layer-it-builds-on&quot;&gt;The protocol layer it builds on&lt;/h3&gt;
&lt;p&gt;UCP.travel does not replace the Universal Commerce Protocol. It extends it for travel.&lt;/p&gt;
&lt;p&gt;UCP defines the checkout lifecycle, identity linking, AP2 mandates, and commerce interoperability. It was built for retail. Retail has stable SKUs, fixed prices, and shipping fulfillment. Travel has none of these. Travel has perishable offers, real-time repricing, passenger identity requirements, asynchronous booking confirmations, and supplier-specific policy enforcement.&lt;/p&gt;
&lt;p&gt;The travel.ucp.* namespace handles what the base spec has no primitives for: offer TTL, price revalidation, cancellation timelines, loyalty accounts, passenger age derivation, and codeshare booking references. These are not optional. Every one of them is a failure mode in production if not handled.&lt;/p&gt;
&lt;p&gt;The charter organizations will eventually build toward this. Building on top of a 40-year-old distribution assumption is a different starting point than building for agents from day one.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-this-means-for-developers-building-travel-agents&quot;&gt;What this means for developers building travel agents&lt;/h3&gt;
&lt;p&gt;If you are building an AI travel assistant today, you are probably doing one of two things.&lt;/p&gt;
&lt;p&gt;You are wrapping a travel search API in an MCP tool and presenting results to a user who then books manually. The agent is a research layer. The human is the execution layer. This is not autonomous booking.&lt;/p&gt;
&lt;p&gt;Or you are trying to complete the booking autonomously and hitting the wall: expired offers, silent price changes, 3DS challenges your agent cannot complete, 202 responses your agent retries into double charges.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://ucp.travel&quot;&gt;UCP.travel&lt;/a&gt; is the runtime that removes that wall. The agent calls tools. The runtime handles offer lifecycle, mandate verification, identity, and payment. The booking completes. The PNR comes back.&lt;/p&gt;
&lt;p&gt;The traveler sets up once: authenticates, signs a mandate defining their booking constraints, connects their AI assistant via OAuth. After that, every booking within those constraints is autonomous.&lt;/p&gt;
&lt;p&gt;That is not an assistant. That is an execution runtime.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-infrastructure-sequence&quot;&gt;The infrastructure sequence&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;HTTP answered:     &quot;How do computers communicate?&quot;

OAuth answered:    &quot;Who is allowed to act?&quot;

MCP answered:      &quot;How do agents invoke tools?&quot;

UCP answers:       &quot;How do systems exchange commerce?&quot;

The remaining question is:

                   &quot;Who is trusted to execute the transaction?&quot;

That is the execution layer.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each layer in this sequence solved a problem the layer below it could not. Each one was called unnecessary by people who could not yet see the applications it would enable.&lt;/p&gt;
&lt;p&gt;The applications that require autonomous travel execution are not theoretical. Corporate travel management at agent scale. AI-driven itinerary optimization that books, not just suggests. Travel policy enforcement that operates at the moment of transaction, not after the receipt arrives.&lt;/p&gt;
&lt;p&gt;Protocols tell agents how to speak. Execution runtimes decide whether they are allowed to act.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://ucp.travel&quot;&gt;UCP.travel&lt;/a&gt; is built by &lt;a rel=&quot;nofollow&quot; href=&quot;https://zologic.nl&quot;&gt;Zologic&lt;/a&gt;. The manifest is public at &lt;a rel=&quot;nofollow&quot; href=&quot;https://ucp.travel/.well-known/ucp&quot;&gt;ucp.travel/.well-known/ucp&lt;/a&gt;. UCPChecker verification: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ucpchecker.com/status/ucp.travel&quot;&gt;ucpchecker.com/status/ucp.travel&lt;/a&gt;. The booking demonstration is documented at &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/zologic&quot;&gt;dev.to/zologic&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21415/the-stack-nobody-talks-about-why-travel-needs-an-execution-runtime</guid>
<pubDate>Fri, 26 Jun 2026 13:54:45 +0000</pubDate>
</item>
<item>
<title>I Replaced a Returns Portal with Five MCP Tools. Here's What Actually Happened.</title>
<link>https://coderlegion.com/18242/i-replaced-a-returns-portal-with-five-mcp-tools-heres-what-actually-happened</link>
<description>&lt;p&gt;Most &quot;AI commerce&quot; demos are still just chat layered on top of old flows.&lt;/p&gt;
&lt;p&gt;Tonight we did something different.&lt;/p&gt;
&lt;p&gt;We ran a live WooCommerce journey where a model searched products, completed a purchase, and then handled a return with keep-offer logic. Not on a mock store. Not with human agents behind the curtain. Through UCPReady and KeepCard.io on protocol-native rails.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-transcript-in-one-line&quot;&gt;The transcript in one line&lt;/h3&gt;
&lt;p&gt;Customer asked for a face cleanser. Model searched the live WooCommerce catalog. Customer bought two products. Checkout ran through UCPReady. Order completed. Customer changed their mind. KeepCard.io verified the order, surfaced the line items, collected the reason, and presented a keep offer. Customer accepted. A real discount code was generated. A real confirmation email was sent.&lt;/p&gt;
&lt;p&gt;That is the entire commerce loop in one conversational journey.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-actually-happened&quot;&gt;What actually happened&lt;/h3&gt;
&lt;p&gt;The session started like a normal shopping flow. The model searched a live WooCommerce store, found products, built a checkout, selected fulfillment, selected payment, and moved through the purchase flow using UCPReady.&lt;/p&gt;
&lt;p&gt;Then in the same session we tested returns through KeepCard.io.&lt;/p&gt;
&lt;p&gt;The return flow did this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Looked up the order by order number and email&lt;/li&gt;
&lt;li&gt;Checked eligibility&lt;/li&gt;
&lt;li&gt;Collected the return reason&lt;/li&gt;
&lt;li&gt;Evaluated keep-offer logic&lt;/li&gt;
&lt;li&gt;Presented the customer with a keep offer in chat&lt;/li&gt;
&lt;li&gt;Accepted the offer&lt;/li&gt;
&lt;li&gt;Generated a real discount code&lt;/li&gt;
&lt;li&gt;Sent the confirmation email&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We saw the discount code issued. We saw the email arrive. We saw the KeepCard dashboard record the return session as Kept.&lt;/p&gt;
&lt;p&gt;That is not &quot;AI-assisted support.&quot; That is a real agentic commerce lifecycle.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;a-real-example-from-tonight&quot;&gt;A real example from tonight&lt;/h3&gt;
&lt;p&gt;The customer started with:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;I want to buy something to clean my face&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The model searched the live catalog and found:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rilastil Aqua Face Cleanser 200ml — €16.95&lt;/li&gt;
&lt;li&gt;Shiseido Men Face Cleanser 125ml — €18.95&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The customer then said:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;buy me 2 of Rilastil Aqua Face Cleanser 200ml and 1 Shiseido Men Face Cleanser 125ml&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The system created checkout, configured fulfillment and wallet payment, and moved the buyer into the final authorization step.&lt;/p&gt;
&lt;p&gt;After the order completed, the customer came back with:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Oh no, I made a mistake — I want to return the item&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The return flow asked for the order number, verified eligibility, and surfaced the exact purchased items:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rilastil Aqua Face Cleanser 200ml (Quantity: 2)&lt;/li&gt;
&lt;li&gt;Shiseido Men Face Cleanser 125ml (Quantity: 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The customer selected only the Shiseido item. Then gave the reason:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Other — I made a mistake&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Instead of routing to a standard return portal, the system evaluated the return and offered a keep option:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;You can keep the Shiseido Men Face Cleanser and receive €1.00 off your next order as a discount code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The customer replied:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Accept&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep offer accepted ✓&lt;/li&gt;
&lt;li&gt;Discount code &lt;code&gt;KEEP-3V9FNM&lt;/code&gt; generated in WooCommerce ✓&lt;/li&gt;
&lt;li&gt;Confirmation email delivered via KeepCard's email stack ✓&lt;/li&gt;
&lt;li&gt;No return shipment needed ✓&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-architecture-what-ucpready-and-keepcard-io-actually-are&quot;&gt;The architecture: what UCPReady and KeepCard.io actually are&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;UCPReady&lt;/strong&gt; is a WooCommerce plugin that implements the Universal Commerce Protocol (UCP) — an open protocol for exposing store capabilities through structured, machine-operable interfaces. It turns a WooCommerce store into a UCP-compliant endpoint that AI agents can discover and transact with autonomously.&lt;/p&gt;
&lt;p&gt;The MCP endpoint on houseofparfum.nl exposes these tools:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;— shopping —
ucp_list_products       ucp_get_product
create_checkout         get_checkout
update_checkout         complete_checkout
cancel_checkout         create_cart
get_cart                update_cart
cancel_cart             convert_cart
ucp_get_order           ucp_list_orders

— returns (KeepCard) —
keepcard_check_return_eligibility
keepcard_select_return_items
keepcard_submit_return_reason
keepcard_accept_keep_offer
keepcard_decline_keep_offer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;KeepCard.io&lt;/strong&gt; is a standalone returns intelligence platform. It connects to WooCommerce via REST API and Shopify via app installation. It owns the decision engine — return eligibility, keep-offer thresholds, fraud signals, monthly caps, discount code generation, and email delivery. None of that logic lives in the LLM.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-important-part-no-ai-in-the-business-logic&quot;&gt;The important part: no AI in the business logic&lt;/h3&gt;
&lt;p&gt;There is no hidden LLM orchestration inside the return engine. There is no model deciding business logic in the backend. There is no &quot;if Claude says X, do Y&quot; architecture.&lt;/p&gt;
&lt;p&gt;The business logic is deterministic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Return eligibility&lt;/li&gt;
&lt;li&gt;Order verification&lt;/li&gt;
&lt;li&gt;Keep-offer thresholds&lt;/li&gt;
&lt;li&gt;Duplicate protection&lt;/li&gt;
&lt;li&gt;Policy routing&lt;/li&gt;
&lt;li&gt;Store credit and discount issuance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The model is only the interface layer.&lt;/p&gt;
&lt;p&gt;That makes the system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model-agnostic&lt;/strong&gt; — Claude, GPT-5, Gemini, Grok all work&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easier to audit&lt;/strong&gt; — no prompt-based rules buried in a system prompt&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easier to harden&lt;/strong&gt; — business rules are code, not inference&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More future-proof&lt;/strong&gt; — swap the model, the commerce layer stays the same&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The same session ran successfully with both Claude Sonnet 4.5 and GPT-5. Neither needed store-specific prompting. The protocol carries the context.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;how-the-return-flow-chains-through-ucpready&quot;&gt;How the return flow chains through UCPReady&lt;/h3&gt;
&lt;p&gt;The full call chain looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Agent → UCPReady MCP endpoint (WooCommerce)
      → KeepCard /api/mcp/* (cloud service)
      → WooCommerce or Shopify API (order verification)
      → KeepCard decision engine (keep-offer logic)
      → WooCommerce API (discount code creation)
      → KeepCard email stack (confirmation)
      → back through the chain to the agent
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The LLM sees clean structured responses at each step:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;// keepcard_check_return_eligibility response
{
  &quot;eligible&quot;: true,
  &quot;session_id&quot;: &quot;...&quot;,
  &quot;needs_item_selection&quot;: true,
  &quot;customer_message&quot;: &quot;I found order #85774. You have 30 day(s) left to return it. Which item(s) would you like to return?&quot;,
  &quot;order&quot;: {
    &quot;display_id&quot;: &quot;85774&quot;,
    &quot;items&quot;: [...],
    &quot;currency&quot;: &quot;EUR&quot;,
    &quot;days_remaining&quot;: 30
  }
}

// keepcard_accept_keep_offer response
{
  &quot;outcome&quot;: &quot;kept&quot;,
  &quot;discount_code&quot;: &quot;KEEP-3V9FNM&quot;,
  &quot;amount&quot;: 1.00,
  &quot;currency&quot;: &quot;EUR&quot;,
  &quot;email_sent&quot;: true,
  &quot;customer_message&quot;: &quot;Done! Your discount code is KEEP-3V9FNM — worth 1.00 EUR off your next order. A confirmation has been sent to your email.&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-broke-because-honesty-matters-&quot;&gt;What broke (because honesty matters)&lt;/h3&gt;
&lt;p&gt;Tonight was not a perfect demo, and that is exactly why it was valuable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. The keep-offer accept step was occasionally slow.&lt;/strong&gt; The final &lt;code&gt;keepcard_accept_keep_offer&lt;/code&gt; step sometimes exceeded the runner timeout budget. The business action still completed but the agent runner could report failure because the round trip took too long. This is a latency problem, not a logic problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Duplicate finalization needed hardening.&lt;/strong&gt; When the first accept completed but the runtime retried, the system needs to treat the retry as a successful terminal state rather than an error. Repeated accept should return: already processed, discount code, final state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Mixed shopping and returns in one session exposed session contamination.&lt;/strong&gt; Running search, purchase, and return inside a single session exposed a session-context boundary problem: return tools were receiving stale search arguments from the earlier shopping flow. The kind you only discover once the stack is real enough to chain these experiences together.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;where-we-go-next&quot;&gt;Where we go next&lt;/h3&gt;
&lt;p&gt;The hardest question has been answered: can a model search, buy, and then resolve a return with keep-offer logic on a live WooCommerce store through protocol-native rails?&lt;/p&gt;
&lt;p&gt;Yes. Tonight, it did.&lt;/p&gt;
&lt;p&gt;The remaining work is hardening, not architecture:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduce latency on the post-purchase bridge&lt;/li&gt;
&lt;li&gt;Keep terminal actions idempotent across retries&lt;/li&gt;
&lt;li&gt;Isolate session state between shopping and returns flows&lt;/li&gt;
&lt;li&gt;Test identity linking across multi-session journeys&lt;/li&gt;
&lt;li&gt;Validate the same lifecycle across more stores&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the remaining problems are latency budgets, idempotency, and session context boundaries — you are no longer asking whether the concept works. You are refining a working system.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-bigger-idea&quot;&gt;The bigger idea&lt;/h3&gt;
&lt;p&gt;The goal is not &quot;AI can help with returns.&quot;&lt;/p&gt;
&lt;p&gt;The goal is: &lt;strong&gt;stores should become operable by agents through standard protocols.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Search is one capability. Checkout is one capability. Payment is one capability. Returns are one capability. Keep-offers are one capability. Once those are exposed properly through open protocol rails, the model becomes interchangeable.&lt;/p&gt;
&lt;p&gt;That is when agentic commerce stops being a gimmick and starts becoming infrastructure.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;UCPReady:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://zologic.nl/ucpready&quot;&gt;zologic.nl/ucpready&lt;/a&gt; — WooCommerce UCP implementation&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;KeepCard.io:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://keepcard.io&quot;&gt;keepcard.io&lt;/a&gt; — Returns intelligence platform&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Session recording:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://ucpplayground.com/s/01KQFVJJK6HZF2Z58MVMZQ3WXP&quot;&gt;ucpplayground.com/s/01KQFVJJK6HZF2Z58MVMZQ3WXP&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Universal Commerce Protocol:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://ucp.dev&quot;&gt;ucp.dev&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/18242/i-replaced-a-returns-portal-with-five-mcp-tools-heres-what-actually-happened</guid>
<pubDate>Mon, 18 May 2026 19:27:55 +0000</pubDate>
</item>
<item>
<title>AP2 Mandates Are Live on UCPReady — Here's What That Actually Means for Autonomous Payment</title>
<link>https://coderlegion.com/15955/ap2-mandates-are-live-on-ucpready-heres-what-that-actually-means-for-autonomous-payment</link>
<description>&lt;p&gt;Zero merchants in &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/benjifisher/agentic-commerce-optimization-what-4491-merchants-reveal-about-ucp-readiness-3fk&quot;&gt;Ben Fisher's 4,024-merchant UCP dataset&lt;/a&gt; support native payment. I've been building toward closing that gap since March. Today it's done — at least on the business side.&lt;/p&gt;
&lt;p&gt;This post is about AP2 Mandates: what they are, why they're the only spec-compliant path to autonomous card payment on UCP, and what it took to implement them correctly on WooCommerce.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-every-ucp-checkout-still-ends-with-a-browser-redirect&quot;&gt;Why every UCP checkout still ends with a browser redirect&lt;/h3&gt;
&lt;p&gt;When an AI agent completes a UCP checkout today, it gets a &lt;code&gt;continue_url&lt;/code&gt;. The buyer clicks a link, lands on the WooCommerce checkout page, fills in their card, and pays. The agent handled discovery and session setup. The human handled payment.&lt;/p&gt;
&lt;p&gt;That handoff exists because the spec requires it — unless one specific extension is active.&lt;/p&gt;
&lt;p&gt;From the UCP checkout specification:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;The checkout has to be finalized manually by the user through a trusted UI &lt;strong&gt;unless the AP2 Mandates extension is supported&lt;/strong&gt;.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That &quot;unless&quot; is the entire autonomous payment story in UCP. Not Stripe tokens. Not saved cards. Not wallet APIs. &lt;strong&gt;AP2 Mandates.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-ap2-mandates-actually-are&quot;&gt;What AP2 Mandates actually are&lt;/h3&gt;
&lt;p&gt;AP2 is a cryptographic authorization framework. When it's negotiated between a business and a platform, the checkout session is &quot;security locked&quot; — neither party can revert to an unprotected flow.&lt;/p&gt;
&lt;p&gt;The flow has two sides:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Business side:&lt;/strong&gt; Every checkout response must include &lt;code&gt;ap2.merchant_authorization&lt;/code&gt; — a JWS detached signature proving the checkout terms (price, line items, totals) are authentic and haven't been tampered with. The signature is ES256, JCS-canonicalized per RFC 8785, with the payload excluded from the JWS body (RFC 7515 Appendix F detached content format).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Platform side:&lt;/strong&gt; When the user confirms the purchase, the platform generates a cryptographically signed mandate — an SD-JWT credential proving the user explicitly authorized this specific transaction. It submits that mandate at &lt;code&gt;complete_checkout&lt;/code&gt;. The business verifies it. If valid, payment proceeds without a browser redirect.&lt;/p&gt;
&lt;p&gt;The checkout mandate contains the full checkout response including the business's &lt;code&gt;merchant_authorization&lt;/code&gt;. So the platform's signature covers the business's signature. It's a nested cryptographic binding: the business proves the terms, the platform proves the user consented to those exact terms.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-implementing-this-actually-required&quot;&gt;What implementing this actually required&lt;/h3&gt;
&lt;h4 id=&quot;getting-the-signing-right&quot;&gt;Getting the signing right&lt;/h4&gt;
&lt;p&gt;The spec says ES256 with detached JWS. In PHP, &lt;code&gt;openssl_sign()&lt;/code&gt; on a P-256 key produces a DER-encoded ECDSA signature. JWS ES256 requires raw &lt;code&gt;r||s&lt;/code&gt; — 64 bytes for P-256. Those are not the same format.&lt;/p&gt;
&lt;p&gt;Every JWS library you'd use on the platform side (jose, python-jose, jsonwebtoken) expects raw r||s. A DER signature will fail verification silently or throw a malformed signature error. The fix is a DER-to-raw-rs converter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// openssl_sign() → DER. JWS ES256 → raw r||s. Not the same.
openssl_sign( $signing_input, $signature_der, $private_key, OPENSSL_ALGO_SHA256 );
$r = substr( $der_inner, $r_offset, $r_len );
$s = substr( $der_inner, $s_offset, $s_len );
$signature_raw = str_pad( ltrim($r, &quot;\x00&quot;), 32, &quot;\x00&quot;, STR_PAD_LEFT )
               . str_pad( ltrim($s, &quot;\x00&quot;), 32, &quot;\x00&quot;, STR_PAD_LEFT );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The JCS canonicalization (RFC 8785) is the other non-obvious requirement. Before signing, the checkout payload is canonicalized — keys sorted recursively, Unicode normalized, numbers in IEEE 754 format. This ensures the signature is reproducible across systems that may re-serialize JSON differently.&lt;/p&gt;
&lt;h4 id=&quot;enforcing-the-mandate-at-complete-checkout&quot;&gt;Enforcing the mandate at complete_checkout&lt;/h4&gt;
&lt;p&gt;The spec is explicit: if AP2 was negotiated, &lt;code&gt;complete_checkout&lt;/code&gt; MUST reject requests without &lt;code&gt;ap2.checkout_mandate&lt;/code&gt;. This is the security boundary. Without it, AP2 is advertised but provides no protection — a platform could skip the mandate entirely and the checkout would succeed.&lt;/p&gt;
&lt;p&gt;The enforcement block runs before order creation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;if ( $ap2_ext-&amp;gt;is_ap2_configured() ) {
    $mandate_jwt = $body['ap2']['checkout_mandate'] ?? null;
    if ( empty( $mandate_jwt ) ) {
        // Return mandate_required error — session stays ready_for_complete
        return $this-&amp;gt;mandate_error_response( 'mandate_required', $session );
    }
    $mandate_error = $ap2_ext-&amp;gt;verify_checkout_mandate( $mandate_jwt, $session, $request );
    if ( null !== $mandate_error ) {
        return $this-&amp;gt;mandate_error_response( $mandate_error['code'], $session );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;verifying-the-mandate&quot;&gt;Verifying the mandate&lt;/h4&gt;
&lt;p&gt;When a mandate is present, the full verification chain runs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Parse the SD-JWT structure (&lt;code&gt;header.payload.signature~disclosures~keybinding&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Check expiry (&lt;code&gt;exp&lt;/code&gt; claim)&lt;/li&gt;
&lt;li&gt;Extract the embedded checkout from mandate claims&lt;/li&gt;
&lt;li&gt;Re-verify &lt;code&gt;merchant_authorization&lt;/code&gt; — confirm the platform wrapped our own signature, not a different checkout&lt;/li&gt;
&lt;li&gt;Verify checkout ID matches the current session&lt;/li&gt;
&lt;li&gt;Verify totals match — no bait-and-switch between what the user saw and what gets charged&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;platform-key-verification&quot;&gt;Platform key verification&lt;/h4&gt;
&lt;p&gt;The final step: verifying the SD-JWT outer signature using the platform's public key. This is what proves the mandate is genuinely from the platform and not forged.&lt;/p&gt;
&lt;p&gt;The flow: decode the JWS header → extract &lt;code&gt;alg&lt;/code&gt; and &lt;code&gt;kid&lt;/code&gt; → fetch the platform's UCP profile from the &lt;code&gt;UCP-Agent&lt;/code&gt; header → pull &lt;code&gt;signing_keys&lt;/code&gt; → find the JWK matching &lt;code&gt;kid&lt;/code&gt; → build an OpenSSL public key from the JWK &lt;code&gt;x&lt;/code&gt;/&lt;code&gt;y&lt;/code&gt; coordinates → verify.&lt;/p&gt;
&lt;p&gt;Building an EC public key from JWK coordinates without a library means constructing the SubjectPublicKeyInfo DER by hand in PHP — OID encoding, SEQUENCE wrapping, BIT STRING for the uncompressed EC point. It's ~80 lines but removes a runtime dependency and works on any WordPress host.&lt;/p&gt;
&lt;p&gt;The platform profile is fetched over HTTPS and cached with WP transients, respecting &lt;code&gt;Cache-Control max-age&lt;/code&gt; with a 60-second floor. Verification result is logged with kid, algorithm, and session ID for auditability.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-capability-name-that-broke-everything&quot;&gt;The capability name that broke everything&lt;/h3&gt;
&lt;p&gt;Before any of this verification mattered, there was a simpler bug: the capability was advertised as &lt;code&gt;dev.ucp.shopping.ap2_mandates&lt;/code&gt; — plural. The spec uses &lt;code&gt;dev.ucp.shopping.ap2_mandate&lt;/code&gt; — singular.&lt;/p&gt;
&lt;p&gt;Capability negotiation is a string equality check. The intersection algorithm finds no match between &lt;code&gt;ap2_mandates&lt;/code&gt; and &lt;code&gt;ap2_mandate&lt;/code&gt;. AP2 is never activated. Every checkout session falls back to delegate payment. No error, no warning — it silently never negotiates.&lt;/p&gt;
&lt;p&gt;One character. Every implementation should validate capability names against the spec registry rather than trusting their own strings.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-s-live-now&quot;&gt;What's live now&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;dev.ucp.shopping.ap2_mandate&lt;/code&gt; is enabled in UCPReady and a compatible platform connects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every checkout response includes &lt;code&gt;ap2.merchant_authorization&lt;/code&gt; (JWS ES256, detached, JCS payload)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;complete_checkout&lt;/code&gt; rejects requests without &lt;code&gt;ap2.checkout_mandate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Verification runs: SD-JWT parse → expiry → embedded checkout extraction → merchant_authorization re-verification → ID and totals match → platform key verification&lt;/li&gt;
&lt;li&gt;If all checks pass, payment proceeds — no browser redirect&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The one remaining piece is ecosystem readiness: a platform that supports AP2 mandate submission and forwards the access token that proves identity linking. &lt;a rel=&quot;nofollow&quot; href=&quot;https://ucpplayground.com&quot;&gt;Ben Fisher's UCPPlayground&lt;/a&gt; is the logical first test. Once that's connected, UCPReady will produce the first confirmed AP2-mandate-verified autonomous purchase on WooCommerce.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-this-matters-beyond-woocommerce&quot;&gt;Why this matters beyond WooCommerce&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/benjifisher/the-state-of-agentic-commerce-april-2026-l93&quot;&gt;Ben's dataset of 4,024 merchants&lt;/a&gt; shows zero native payment support. Part of that is the SPT/ACS story — Stripe's Shared Payment Token is US-only right now and requires Stripe to host the checkout flow. That's a different architecture than UCP.&lt;/p&gt;
&lt;p&gt;On UCP, AP2 Mandates is the spec's answer. It's protocol-agnostic — the mandate can cover any payment method handled by any PSP. The platform proves user consent cryptographically. The business verifies that proof and charges via their existing payment gateway. No card data crosses protocol boundaries. PSD2 SCA compliance comes from the mandate being platform-issued and buyer-authenticated at mandate creation time.&lt;/p&gt;
&lt;p&gt;This is what autonomous agent commerce looks like when the merchant controls the checkout instead of delegating it to Stripe's infrastructure.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;UCPReady is available at &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://zologic.nl/ucpready&quot;&gt;zologic.nl/ucpready&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you're building a platform that supports UCP and want to test AP2 mandate submission against a live endpoint, reach out. houseofparfum.nl is running UCPReady 1.8.23 with AP2 ready to activate.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/15955/ap2-mandates-are-live-on-ucpready-heres-what-that-actually-means-for-autonomous-payment</guid>
<pubDate>Mon, 27 Apr 2026 09:00:29 +0000</pubDate>
</item>
</channel>
</rss>