Skip to content

feat(shopping): Add additional fields proposal (from Shopify)#481

Open
SaifBenChahed wants to merge 7 commits into
Universal-Commerce-Protocol:mainfrom
SaifBenChahed:additional-fields-v3
Open

feat(shopping): Add additional fields proposal (from Shopify)#481
SaifBenChahed wants to merge 7 commits into
Universal-Commerce-Protocol:mainfrom
SaifBenChahed:additional-fields-v3

Conversation

@SaifBenChahed

@SaifBenChahed SaifBenChahed commented May 26, 2026

Copy link
Copy Markdown

Summary

Adds an Additional Fields proposal using a single extension with optional config-based type narrowing.

Businesses sometimes need to collect checkout data that is specific to their workflow, such as PO numbers, gift options, delivery notes, requested dates, or buyer acknowledgements. Today there is no standard way for a business to describe those fields to a platform, for the platform to collect values, or for captured values to appear on orders.

This proposal standardizes that exchange:

  • checkout additional_fields definitions and submitted values
  • order read-only additional field summaries
  • standard input types: text, boolean, date, and choice
  • text validation hints, multiline text, date bounds, and choice options
  • validation errors through existing messages[]

It also adds optional config.supported_types on the capability. Platforms and businesses may use supported_types to narrow the active type set; when both declare it, the active set is their intersection.

Notes

The payload schema remains the full standard type superset. Config is treated as an optional negotiation constraint, not the primary extension model.

@SaifBenChahed
SaifBenChahed force-pushed the additional-fields-v3 branch from 0f3f644 to 7ddded6 Compare May 27, 2026 18:04
@SaifBenChahed
SaifBenChahed force-pushed the additional-fields-v3 branch from 7ddded6 to d89904f Compare May 27, 2026 18:24
@SaifBenChahed SaifBenChahed changed the title Add additional fields config proposal Add additional fields proposal May 27, 2026
@SaifBenChahed
SaifBenChahed marked this pull request as ready for review May 28, 2026 15:43
@SaifBenChahed
SaifBenChahed requested review from a team as code owners May 28, 2026 15:43
@SaifBenChahed SaifBenChahed changed the title Add additional fields proposal Add additional fields proposal (from Shopify) May 28, 2026
@SaifBenChahed SaifBenChahed changed the title Add additional fields proposal (from Shopify) feat: Add additional fields proposal (from Shopify) May 29, 2026
@SaifBenChahed SaifBenChahed changed the title feat: Add additional fields proposal (from Shopify) eat(shopping): Add additional fields proposal (from Shopify) May 29, 2026
@SaifBenChahed SaifBenChahed changed the title eat(shopping): Add additional fields proposal (from Shopify) feat(shopping): Add additional fields proposal (from Shopify) May 29, 2026
@SaifBenChahed

Copy link
Copy Markdown
Author

cc @igrigorik @richmolj

@jamesandersen jamesandersen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@SaifBenChahed thanks for submitting this! I think this will unlock agentic commerce for a non-trivial cohort of merchants requiring some incidental extra inputs.

Comment thread docs/specification/additional-fields.md
Comment thread docs/specification/additional-fields.md Outdated
Comment thread docs/specification/order-additional-fields.md
"ucp_request": "omit"
},
"value": {
"type": [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just a thought, for booleans, might consider making the base value accept a union, then use the same if/then pattern the PR already uses for input to pin boolean-typed fields to a real boolean:

// additional_field.value base type:
"value": { "type": ["string", "boolean", "null"], ... }

// additional_field.allOf — add:
{
"if": {
"properties": { "input": { "properties": { "type": { "const": "boolean" } }, "required": ["type"] } },
"required": ["input"]
},
"then": { "properties": { "value": { "type": ["boolean", "null"] } } }
}

Request becomes { "key": "gift_wrap", "value": true }, cleared as { "key": "gift_wrap", "value": null }.

Otherwise I'd just add some language indicated the expected string formats for boolean values

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks, that makes sense. The conditional schema approach would work well for responses, since each field includes input.type.
For submissions, though, we only send key + value, without the field definition. The business still needs to resolve the key back to its field definition to validate type-specific rules, whether that rule is boolean format, choice membership, date bounds, or text constraints.
My slight preference is to keep value as string | null here for a uniform submission shape, so I added normative language that non-null boolean values MUST be the exact strings "true" or "false".

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

While there's a preference for machine resolvable schema, this seems reasonable; we'll see if there's any second opinion here ;-)

@igrigorik igrigorik added the TC review Ready for TC review label Jun 21, 2026
Comment thread docs/specification/additional-fields.md Outdated
@damaz91
damaz91 removed request for a team, aksbro-gpu, damaz91, mmohades and westeezy July 14, 2026 08:31
@damaz91 damaz91 added gov:needs-gc-review status:needs-triage Signal that the PR is ready for human triage and removed status:needs-triage Signal that the PR is ready for human triage labels Jul 14, 2026

### Checkout Extension

{{ extension_fields('additional_fields', 'additional-fields') }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it should be {{ extension_fields('additional_fields', 'checkout') }}

@jingyli jingyli left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the proposal! Some fundamental questions I had:

  1. [Discussed and aligned on most, would love to see if it would be good to consider adding a section in overview.md to clarify best practices on the use cases and scenarios further] Now in UCP, we will have multiple mechanisms to allow data to be collected on top of the main request & response wiring: 1) embedded transport via continue_url, 2) escalation redirect handoff via continue_url, 3) new actions construct being introduced in #582. How should implementators think about when to use what - let's take an example of needing to collect a user's age for verification, I can naively see it fall into all 4 buckets - what would be best practices and guidelines we set around them? Or is this something we don't want to get into at all and leave it to the implementors to define?
  2. With this extension's vast flexibility to support various use cases, what are the principles we will now hold to decide what use cases to promote into UCP as first-class citizens vs. just re-leveraging this extension? An example can be scheduled delivery: this extension will be able to support the collection of its values, but I do see a path to also model this directly into the fulfillment extension.
  3. I see the scope of this extension, so far, is only decorating checkout & order (which is 100% fine to start with a narrow scope). But I'm curious what are our thoughts on this extension decorating other capabilities like cart or even going beyond shopping service?
  4. Are there other data (on top of the supported type) we want to negotiate up front between platforms & businesses when using this extension? An example: a platform may have UI wiring for type = choice, but it can only display up to 5 options. Then should that restriction be negotiated up-front?
  5. Any guidelines we should set for businesses & platforms on rendering contracts? What about privacy & security considerations since now platforms will need to dynamically understand/interpret data needs from businesses and collect/disclose them from the user?

Each field definition includes an `input` object with a required `type` string.
Platforms SHOULD respect the declared type. Platforms that do not recognize a
type SHOULD NOT render it as a different supported type, coerce it to text, or
collect a value unless a negotiated extension defines that type.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Trying to unpack this sentence here along with the Standard Input Types below and the schema design. Is it correct to interpret this as:

  • UCP defines 4 well-known input types (essentially authored and endorsed by UCP governing body) = the standard input types
  • Platforms & businesses can negotiate on other primitive supported input types (for example, "number" for numeric input) out-of-band. When the same input value is advertised and negotiated, then it can be leveraged as-is.

My confusion is around what we mean by "a negotiated extension defines that type"? Are we talking about the fact that we can have something like com.example.number as a type value? Can we bring some clarity in the sentence here by giving some examples? Also some naive questions on top:

  • How are we thinking of mapping type value (i.e.number) to the actual input schema (i.e. com.example.number) for these custom extensions?
  • How would we advertise these custom type extensions in the UCP profile?

Would we have:

"dev.ucp.shopping.additional_fields": [
        {
           ...
          "config": {
            "supported_types": ["text", "boolean", "com.example.number"]
          }
        }
      ],
"com.example.number": [
    {
       ....
       extends: "dev.ucp.shopping.additional_fields"
    }
]

If yes to the example above, then I believe this may be the first time where an extension is now extending another extension explicitly in UCP (not saying this is not okey, but just want to explicitly call it out this is the first time UCP is broadly advocating for this kind of pattern).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Read through Extensibility section below and it aligned with my understanding/assumption in the comment, though some additional clarity in language & examples would still be nice here 😃.

However, the 2 naive questions bullet still hold:1) Are we expecting the reverse-DNS to be part of supported_types? 2) This is the first instance of extension decorating an extension.


### Standard Input Types

This version defines the following standard types:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Curious how did we land on the standard types here? Did we evaluate other primitives like numeric and/or list inputs to be a well-known value?

"dev.ucp.shopping.additional_fields": [
{
"version": "{{ ucp_version }}",
"extends": "dev.ucp.shopping.order",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Trying to envision the scenario where dev.ucp.shopping.additional_fields is supported only in order but not checkout in UCP. In checkout, let's say platform opted to redirect/hand off user to business for collection of these values. If the extension is supported in order, does that mean platform would still get back those values through this structured additional_fields extension for read-only?

Or is there a strong dependency that values returned here MUST be collected via the extension when decorating UCP checkout?

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants