Skip to content

Conversation

@igrigorik
Copy link
Contributor

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. Practically, merchants would treat it as a hint and ignore it for anything they don't explicitly allow.

Correct model: buyer provides context signals (country, region, postal code, affiliations), 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 & used by catalog, cart, and checkout.


Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation

@igrigorik igrigorik requested review from a team and drewolson-google January 16, 2026 06:03
@igrigorik igrigorik self-assigned this Jan 16, 2026
@igrigorik igrigorik added this to the Working Draft milestone Jan 16, 2026
Copy link

@amithanda amithanda left a comment

Choose a reason for hiding this comment

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

I am wondering if there will be use cases where there is an explicit buyer preference to see amounts in a specified currency, although I'll admit that I have not seen this to be super common e.g shoppers from different country choosing to pay in local v/s foreign currency.

@drewolson-google
Copy link
Collaborator

I am wondering if there will be use cases where there is an explicit buyer preference to see amounts in a specified currency, although I'll admit that I have not seen this to be super common e.g shoppers from different country choosing to pay in local v/s foreign currency.

In the past, I've seen this modeled as presentment_currency and settlement_currency. With this modeling, presentment_currency could be an input, but there would likely need to be a merchant negotiation to determine what set of presentment_currency values are support, as doing real-time currency conversion can be complicated for the merchant.

@igrigorik
Copy link
Contributor Author

In the past, I've seen this modeled as presentment_currency and settlement_currency. With this modeling, presentment_currency could be an input, but there would likely need to be a merchant negotiation to determine what set of presentment_currency values are support, as doing real-time currency conversion can be complicated for the merchant.

@drewolson-google @amithanda yep, these are the right concepts. Our currency field is effectively presentment currency - what the merchant presents to the buyer. The key thing here is: currency selection is merchant-controlled because arbitrary conversions open forex risk and create a gap between what's presented and what's settled. Merchants configure which currencies they support per market, not per-request.

The contract we're establishing: buyer provides context signals, merchant selects the appropriate currency for this transaction. From there, everything is consistent end-to-end - what you see is what you pay.

  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.
  Doc generator previously required every $ref property to duplicate the
  referenced type's description. This violated DRY - same description
  copied everywhere, diverging over time.

  New behavior:
  - Embedder provides description → use it (custom/contextual)
  - Embedder omits description → inherit from ref'd type

  JSON Schema allows omitting description, so embedders can now choose:
  override with context-specific text, or inherit the canonical definition.
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.
@igrigorik
Copy link
Contributor Author

We had a good out-of-band discussion on this, recapping where we landed...

Buyer signals fall into two categories with different contracts: provisional context and authoritative selections. Provisional context is progressively disclosed, non-identifying information that helps the business tailor responses before authoritative data exists—"I'm interested in goods that ship to Canada" followed by "My postal code is X if you can do shipping estimates." The buyer/agent can refine context as the session progresses, improving relevance and localization along the way. Authoritative selections are explicit buyer choices that must be honored or rejected—shipping addresses, billing addresses, fulfillment destinations. When a buyer provides these, they're not hinting; they're instructing.

These two types of data require different response contracts. Provisional context can be silently ignored or adjusted: "You indicated interest in MX, but we'll serve you USD because that's what we support." An authoritative selection must be validated and either honored or rejected: "You requested MX as your shipping destination, but we don't ship there—here's an error."

Market determination is merchant-side computation—buyers provide signals, merchants determine market. Currency in the response reflects that determination, derived from context, addresses, and merchant configuration. Buyers don't set markets; they provide progressively richer signals that inform the merchant's determination.

This is why context separates them in the data model. Context holds provisional, progressively-disclosed signals that the business MAY use to tailor responses. Domain entities (buyer, addresses, fulfillment destinations) hold authoritative identity and selections that the business MUST validate and accept or reject. The structure itself signals the contract: buyer email identifies a unique buyer, so it lives on the buyer object; shipping country is an instruction that must be validated, so it lives on the address.

The test for schema authors:

  • Can business silently ignore or adjust this signal? Provisional → context
  • Must business validate and explicitly accept or reject? Authoritative → domain entity

One more topic we explored and deferred: should the response echo what the merchant resolved to? Today, context is input-only—determination is implicit in response fields (currency, shipping methods, etc.). Providing context back on the response would make this directly auditable. The schema is forward-compatible if we want to introduce this later, or via separate fields.

@igrigorik igrigorik requested a review from amithanda January 17, 2026 06:22
@amithanda
Copy link

I agree with the principle here. Maybe I was not clear in my initial comment, what I wanted to check was that within the context object, should we add buyer currency preference as well, in addition to country, address and region code?
If the merchant supports that currency they can provide the response in that currency (with the right exchange rates etc applied to show a more accurate price).
If they don't, then as you mentioned in future, we should provide a context response back conveying to the buyer that merchant does not support that currency and buyer can make a determination to continue.

@amithanda
Copy link

Another use case that comes to my mind, where this may be relevant is e.g when the buyer is traveling and is in a foreign country. They open up a merchant site in their home country, they may have a preference to see currency in their home country currency rather than foreign country currency, if merchant supports both currencies.

@amithanda
Copy link

I am also fine to go ahead with this and add this in future.

Copy link

@knightlin-shopify knightlin-shopify left a comment

Choose a reason for hiding this comment

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

Approved with comments.

@@ -0,0 +1,22 @@
{
Copy link

@knightlin-shopify knightlin-shopify Jan 17, 2026

Choose a reason for hiding this comment

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

"additionalProperties": true is missing?

"properties": {
"address_country": {
"type": "string",
"pattern": "^[A-Z]{2}$",

Choose a reason for hiding this comment

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

nit: This matches the “ISO 3166-1 alpha-2 country code” schema, but it’s inconsistent with address_country in postal_address.json. As hint, should we accept lowercase values as well (e.g., ^[A-Za-z]{2}$)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants