Skip to content

Conversation

@jingyli
Copy link
Contributor

@jingyli jingyli commented Jan 24, 2026

Reopening the PR to avoid recreating the working-draft branch. This is a mirror copy of #109 and will also cross-reference/carry-over comments from the old PR.

Summary

Cart capability (dev.ucp.shopping.cart) is being introduced in #73. This adds an additional transport binding (EP) on the capability (building directly upon the referenced PR), on top of existing REST & MCP bindings.

Motivation

Businesses need a way to embed their cart building UI into eligible platforms, especially when complex experiences (i.e. item recommendations & upsells) are involved during cart building. Embedded Cart Protocol (ECaP) addresses this need and also offers a seamless connection to existing Embedded Checkout Protocol to continue the purchase experience.

Goals

  • Enable businesses to embed cart UI into eligible hosts in a secure manner, especially if identity linking is a required pre-requisite for the flow.
  • Provide seamless transition between embedded protocols to enable cart-to-checkout conversions.
  • Maintain general schema & design consistency with existing ECP (i.e. reuse naming conventions, message types, etc.)
    • There remains some fundamental design differences in the design (i.e. host-initiated notification to share required authorization data, change requests that require host responses, etc.)

Non-Goals

Detailed Design

Key methods supported by ECaP:

Category Communication Direction Purpose Pattern Core Messages
Handshake Embedded Cart -> Host Establish connection between host and Embedded Cart. Request ect.ready
Authentication Host <-> Embedded Cart Communicate auth data exchanges between Embedded Cart and host. Notification & Request ect.auth (Request), ect.auth.change (Notification)
Lifecycle Embedded Cart -> Host Inform of cart state in Embedded Cart. Notification ect.start
Transition Embedded Cart -> Host Establish transition from cart to other capabilities. Request ect.transition.checkout
State Change Embedded Cart -> Host Inform of cart field changes. Notification ect.line_items.change, ect.buyer.change, ect.context.change, ect.messages.change

Protocol transition

  • Introducing a new message type: [protocol namespace].transition.[capability transitioning to] that can be generally extended if conversions between multiple capabilities are possible.
    • First use case we are introducing is ect.transition.checkout that would denote a cart transitioning to a checkout session on the business's iframe.

Risks and Mitigations

  • Complexity: ECaP introduces another transport mechanism to implement & support. Mitigation: Not all businesses need to support it as part of its services advertisement. Also structurally it's also very similar to ECP so businesses already supporting ECP should be familiar with the design already.
  • Security: Introduced new host-initiated notification mechanism ect.auth to exchange required authorization data instead of adding them as query parameters in continue_url to avoid hijacking attacks.
  • Backward Compatibility: None, new transport binding on a new capability.
  • Schema Drift: Not introducing any new schemas, only new methods that utilizes existing schema components.

Graduation Criteria

Working Draft → Candidate:

  • Schema merged and documented (with Working Draft disclaimer).
  • Unit and integration tests are passing.
  • Initial documentation is written.
  • TC majority vote to advance.

Candidate → Stable:

  • Adoption feedback has been collected and addressed.
  • Full documentation and migration guides are published.
  • TC majority vote to advance.

Implementation History

TBD

@jingyli jingyli added the TC review Ready for TC review label Jan 24, 2026
@jingyli jingyli requested a review from a team January 27, 2026 01:07
vulnz
yaml
yml
ZEGTBCTMJ
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional?

yml
ZEGTBCTMJ
llms
paymentmethodchange
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t see this elsewhere in the PR

llms
paymentmethodchange
reauth
reprepare
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a word, I’d suggest rewriting the sentence it’s in instead.

"schema": "https://ucp.dev/services/shopping/mcp.openrpc.json",
"endpoint": "https://merchant.example.com/ucp/mcp"
},
"embedded": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remind me if a business implementing UCP must implement every part of the transport for a given service (e.g., every message in embedded protocol, endpoint/ action in REST/ MCP)? Up until now it had not occurred to me that this might be an issue, since the business I represent would happily implement all the MCP cart actions alongside checkout, but this may not be the case with embedded, where Shopify may prefer to/ temporarily have only the checkout embed messages hooked up.


### Authentication

#### `ect.auth`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think I understand how this message works from the Cart’s perspective. If the Cart sends ec.ready with requires_auth, what do they do while they wait for this auth message to come in? Why wouldn’t the auth be part of the response to that ready message, if it is actually required?

More generally, it’s not clear to me why this would exist for Cart and not Checkout. If a business wanted to enact this same identity linking requirement in Checkout, I assume they would do it with a messages error indicating that identity linking is required, and they would expect a UCP consumer to attach the necessary information before escalating to an embedded cart. Why not follow that same approach here, rather than creating an additional request-response cycle between host and business?

the `ect_` prefix to avoid namespace pollution and clearly distinguish ECaP
parameters from business-specific query parameters:

- `ect_version` (string, **REQUIRED**): The UCP version for this session
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a ect_auth param (as a parallel to ec_auth)? In ECP, that param serves to identify the embedder and to unlock customizations out-of-band from UCP (e.g., the branding overrides of an embedded checkout or cart); I feel this is needed in the initial request for cart in the same way it is for checkout (so the server render of the page can incorporate knowledge of the embedder).


### Transition Messages

#### `ect.transition.checkout`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I noted in my previous review, I feel this message is quite odd. As described, it implies that the buyer would always see a web checkout, and that the same HTML page will morph from cart to checkout, which I do not believe will be a common implementation pattern. It also means that the cart creates the checkout and navigates to it, which requires a separate parallel way to do everything you might do in that transition (you added ec_delegate param as a response, but omitted ec_auth; similarly, there is no way to attach data to create_checkout that is not attached to the cart).

I would have expected a much simpler notification here instead, indicating that the user has attempted to checkout (e.g., something like ect.checkout_request). This puts the embedder in control to use whatever approach to checkout is most appropriate, exactly as they would if they were building their own, non-embedded cart; they can call create_checkout with anything they like, and can construct an ECP URL/ initiate an ECP escalation in the standard way.

changed, items added/removed) in the cart UI. However, it's waiting
for host input (i.e. validating the update to see if it's compliant
with host's requirement) before applying the changes. Embedded Cart
**MUST NOT** fully apply the changes without receiving a response
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "fully apply the changes" mean? I think we need to be more specific here — the embedded checkout would obviously need to indicate something changed, otherwise the buyer would think their edit had been ignored. I also think there should be some sort of guidance on timeouts here, since the action being blocked is one that every implementation would expect to be synronous or near-instant (if I change line item quantity by 1, I do not want to have to wait for 2 seconds to see that change reflected).

occurred partially and depending on host response, the final changes
occur in Embedded Cart.

#### `ec.line_items.change_request`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this exist in cart, but not checkout? I feel we are creating a strange patchwork, where one side has request messages for some fields (fulfillment.address_change_request, payment.credential_request) and the other side has messages for other fields (line_items.change_request). Is there a rule that guides what requests are available where, or is it just, "whatever the first implementers wanted in their particular UX"?

Additionally, should this not be a formal delegation, instead of something that is expected of all embedded carts? We did this for the checkout "let host handle some parts of updates" flows, and I think it applies equally well to this action.

"id": "items_change_request_1",
"result": {
"cart": {
"line_items": [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the host allowed to edit every detail of these lines, or only some aspects?

igrigorik and others added 9 commits February 2, 2026 20:24
  Currency as client input is flawed - merchants control accepted
  currencies, not buyers. Allowing "show me price in $X" implies forex
  operations that break at payment time when the merchant's actual accepted
  currency differs.

  Correct model: buyer provides context signals, merchant determines currency
  and other market-relevant attributes such as product availability,
  shipping and delivery times, price, etc.

  Changes:
  - Add extensible Context type with country, region, postal_code for
    progressive disclosure
  - Add context to checkout (optional on create/update, omit on complete)
  - Make currency output-only (omit on all operations)

  This primitive will be relevant for catalog, cart, and checkout.
Context signals are provisional hints—businesses SHOULD use them when
authoritative data is absent, MAY ignore unsupported values without errors.
This differs from authoritative selections (addresses) which require explicit
validation and error feedback.

Changes:
- Make context input-only (omit from response via ucp_response annotation)
- Add Context entity documentation to checkout spec
- Update context.json description with SHOULD/MAY language
- Update currency description to emphasize merchant determination

Input-only context keeps the door open for future "resolved context" output
that echoes back what the merchant determined, similar to how currency works.
…tem validation to keep ECaP simple for now. We will re-evaluate on the item validation piece as a follow-up.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

TC review Ready for TC review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants