Building a Magento 2 UCP Extension (Docker Dev): The Plan for a Best-in-Class Checkout Experience
2026-01-27
If you’ve ever felt like “checkout is where good shopping experiences go to die,” this project is for you.
We’re going to build a UCP adapter module for Magento 2 — a clean integration layer that exposes a UCP Business Profile and implements the UCP Checkout Capability endpoints, all inside Magento/PHP, using the Docker environment I’ve just set up at:
http://magento.test/
This post is the tutorial / roadmap for what we’re going to make, why it matters, and how we’ll do it step-by-step.
What is UCP and why should we care?
UCP (Universal Commerce Protocol) is a standard way for AI shopping agents and clients to talk to commerce systems. Instead of scraping pages or juggling bespoke APIs, a UCP-compatible store can expose a predictable set of endpoints that support:
- creating a checkout session
- updating it (address, shipping selection, buyer details)
- completing checkout (placing the order)
- cancelling
The key outcome: less friction, fewer bugs, and a better user experience — especially when the “shopper” is an AI agent or an assistant-driven flow.
What we’re building (MVP)
We’ll ship an MVP that’s genuinely useful but not over-scoped.
1) A Business Profile at /.well-known/ucp
This is a JSON document that advertises:
- what UCP capabilities our store supports
- where the checkout REST endpoints live
- version + metadata needed for discovery
Think of it like: “Here’s what my store can do, and here’s where to call it.”
2) Checkout Capability endpoints (implemented in Magento Web API)
We’ll implement the core flows as REST endpoints inside Magento. Internally, they’ll map directly to Magento’s native checkout engine:
- UCP checkout session → Magento quote
- “complete” → place order
This is the heart of the project: we’re turning Magento into a UCP-compatible backend without introducing extra services.
The UX goal: “best shopping experience we can”
This project isn’t “just implement some endpoints.”
We want the flow to feel:
- fast (no unnecessary calls / recalculations)
- clear (the response tells the client what’s missing and what’s next)
- resilient (idempotency, safe retries, consistent session state)
- accurate (totals always match Magento reality: shipping, tax, discounts)
- extensible (we can add payments, post-purchase, and order status later)
So our definition of “done” isn’t “it returns 200 OK” — it’s “it produces a checkout flow you can trust.”
Important: local dev is HTTP… but UCP expects HTTPS
My local Docker site is currently:
http://magento.test/
That’s fine for building and testing logic, but for UCP compliance and realistic integration testing, we’ll add local TLS very early.
What we’ll do:
- Option A (preferred): mkcert + local HTTPS in the Docker reverse proxy
- Option B: tunnel (ngrok / Cloudflare tunnel) if we need quick external HTTPS
We’ll do the simplest thing that gets us to real HTTPS requests fast.
Architecture: keep it simple
We’re not building a separate Python gateway.
Everything will live in a Magento module, roughly like this:
Module responsibilities
- Route
/.well-known/ucp→ return Business Profile JSON - Expose REST endpoints under Magento Web API (e.g.
/rest/V1/ucp/...) - Maintain a mapping table between UCP session IDs and Magento quote IDs
- Translate request payloads into Magento quote updates:
- add/remove items
- set customer email
- set shipping address
- choose shipping method
- totals recollection
- Place the order safely and return an order reference
Data model
We’ll likely add a small table like:
pm_ucp_checkout_sessionsession_id(UCP session id)quote_idstatus(active/completed/cancelled/expired)- timestamps
No over-engineering — just what we need to avoid “where did this quote come from?” chaos.
The build plan (what we’ll do next)
Step 1 — Create the module skeleton
registration.phpmodule.xmletc/di.xmletc/webapi.xml- ACL only if we build admin tooling later
Step 2 — Serve /.well-known/ucp
Two ways:
- static file in pub/.well-known/ucp (fastest)
- or a Magento controller + nginx rewrite (more “Magento-native”)
We’ll probably start static to move fast, then switch to dynamic once the endpoints exist.
Step 3 — Implement checkout session creation
Endpoint: POST /checkout-sessions
Magento behavior: - create a quote - add line items (by SKU) - collect totals - return session payload
Step 4 — Implement update + read
Endpoints:
- GET /checkout-sessions/{id}
- PUT /checkout-sessions/{id}
Magento behavior: - update email / buyer details - update shipping address - recalc shipping rates + totals - return what’s still missing (e.g. “shipping method not selected”)
Step 5 — Implement complete + cancel
Endpoints:
- POST /checkout-sessions/{id}/complete
- POST /checkout-sessions/{id}/cancel
Magento behavior: - complete: place order using quote management - cancel: deactivate quote + mark session cancelled
Step 6 — Make it production-grade
This is where “best experience” actually happens: - idempotency keys for safe retries - consistent error shape + clear messages - logging with request correlation IDs - strict validation (bad SKU, out of stock, invalid shipping method) - expiry rules for sessions
MVP acceptance criteria (the “we can ship it” checklist)
When we’re done with phase 1, we should be able to say:
GET /.well-known/ucpreturns a valid Business Profile JSON.- You can create a UCP checkout session that creates a Magento quote with items.
- You can update session details (email/address) and totals update correctly.
- You can complete the session and Magento places an order successfully.
- You can cancel a session and the quote is safely invalidated.
- Everything works over HTTPS locally (not just HTTP).
Why this is worth doing
Magento checkout is powerful but messy to integrate into “new” shopping experiences.
UCP gives us a clean interface layer that: - lets assistants/agents drive checkout safely - removes fragile, bespoke integration glue - improves reliability and consistency
And because we’re building it as a Magento module, we keep deployment straightforward and avoid extra infrastructure.
Next post
Next up, we’ll do the first real implementation step:
- Create the Magento 2 module
- Expose the first endpoint
- Wire up quote creation + session persistence
If you want to follow along locally, make sure your Docker setup can run Magento cleanly on magento.test, and be ready to add local HTTPS early.
Notes / repo structure (placeholder)
When I publish the code, I’ll include:
/app/code/Vendor/Ucp/- database schema patch for session mapping
- example curl requests to test the endpoints
- a minimal Postman collection
(We’ll keep it lean and focused.)