Shopping with UCP
The Universal Commerce Protocol is the merchant-side language for agentic commerce: standard capabilities for catalog search, checkout, and orders, co-developed by Amazon, Walmart, Shopify, Google, Stripe and others. UCP says how an agent talks to a merchant. It says nothing about whether the agent should — who may spend, from which funds, under what ceiling, with whose approval. That is the kernel.
In UCP’s vocabulary the kernel is the platform. In the kernel’s vocabulary UCP is one more way a governed intent reaches the same gate.
The shape of a purchase
Section titled “The shape of a purchase”discover ──▶ approve ──▶ search ──▶ checkout ──▶ complete ──▶ paid (import) (2nd human) (catalog) (session) (money gate) (witness)- Discover. An operator imports a merchant from its
/.well-known/ucpprofile. The kernel fetches it through its egress guard, checks that every declared capability is served from the domain its name claims (a forged namespace refuses the whole document), negotiates the release and capabilities against the kernel’s own platform profile, and registers the business as a PENDING payee. The operator supplies where money lands; the profile never does. - Approve. A different human approves the payee — the same maker-checker rule as every merchant. A discovered merchant is not a payable one.
- Search. “Which of our merchants sells a latte?” fans
catalog.searchout to approved UCP merchants in the caller’s zones and comes back SKU-level with live prices. Merchants without the capability are reported as skipped, never silently dropped; merchants in another tenant’s zone are never asked. - Checkout. The agent opens a session against a merchant. The kernel re-adds the merchant’s own cost breakdown — exactly one subtotal, one total, entries summing to it — and refuses a session whose numbers lie before it exists. Sessions are durable and idempotent per zone and key: a retried open is never a second purchase.
- Complete. The kernel builds a charge from the total it verified, bound to the operator’s alias, and passes it through the ordinary money gate: policy chain, rolling ceilings, payee registry, spending visa, reservation. Over a ceiling, the agent gets a
202with anapproval_idand the merchant’scontinue_urlfor the human; approving grants authority only, and the agent collects by retrying. - Paid. The merchant’s declared payment handlers, read through the operator’s
[ucp.handlers]mapping, choose the rail. The settlement driver authorizes the payout; the instrument submitted to the merchant is the payout reference — money the provider already accepted, never a credential. A deferred payout is handed to the reconciler; when the provider’s witness lands, the ledger and the order’spayment_statemove together.
What the kernel never trusts
Section titled “What the kernel never trusts”| Claim | Who says it | What the kernel does instead |
|---|---|---|
“I offer dev.ucp.shopping.checkout” |
the profile | validates the schema URL against the namespace authority; refuses forgeries whole |
| “the total is $5.36” | the checkout | re-adds the entries; refuses UCP_TOTALS_MISMATCH |
| “pay me here” | the merchant | pays the operator-bound alias, never a quoted destination |
| “the order is paid” | a webhook | verifies the HMAC, takes only the payout reference, asks the provider |
Surfaces
Section titled “Surfaces”| Route | Plane | Purpose |
|---|---|---|
GET /.well-known/ucp |
every node, public | the kernel’s platform profile — release, capabilities, signing keys |
POST /v1/ucp/import |
control, admin | fetch a profile, negotiate, land a PENDING payee |
GET /v1/merchants/products?q= |
control | SKU-level search across approved UCP merchants |
POST /v1/ucp/checkout · GET …/{id} · POST …/{id}/complete · POST …/{id}/cancel |
data | the session lifecycle; complete runs the money gate |
POST /v1/ucp/webhook |
data, HMAC | the order doorbell; never believed, always verified |
Every UCP surface answers 404 while [ucp] enabled is false.
Configuration
Section titled “Configuration”[ucp]enabled = trueversion = "2026-04-08" # the vendored release; disagreeing with the build fails at bootprofile_ttl = "1h" # cache refresh; staleness is surfaced, never enforcedcatalog_fanout = 5catalog_timeout = "3s"
[ucp.handlers] # merchant handler → kernel rail; explicit only"com.example.processor_tokenizer" = "settlement"Secrets come from the environment, never TOML: STRATUS_UCP_WEBHOOK_SECRET authenticates the order doorbell.
Reading a purchase in the console
Section titled “Reading a purchase in the console”A UCP purchase renders on its trace as a story: Merchant discovered → Catalog searched → Checkout opened → Payment authorized → Payment pending settlement → Payment settled, with the human approval and the branch not taken shown when a ceiling intervened. The payout reference is the join key between “money left” (the payment leg) and “money landed” (the reconciler’s outcome), so a reader can follow one purchase from intent to witness without leaving the page.
Design notes
Section titled “Design notes”The full design is docs/ucp_adapter_hld.md in the repository. Two decisions carry most of the weight: checkout adds no second enforcement path (Complete builds a charge and passes the existing gate), and discovery produces PENDING state only (no profile, however well-signed, moves money without a second human).