Skip to content

feat: add optional display_order to payment handlers#176

Open
prasad-stripe wants to merge 1 commit intoUniversal-Commerce-Protocol:mainfrom
prasad-stripe:feat/payment-handler-display-order
Open

feat: add optional display_order to payment handlers#176
prasad-stripe wants to merge 1 commit intoUniversal-Commerce-Protocol:mainfrom
prasad-stripe:feat/payment-handler-display-order

Conversation

@prasad-stripe
Copy link
Copy Markdown

@prasad-stripe prasad-stripe commented Feb 13, 2026

Payment handler display order (merchant-suggested ordering)

Description

Please include a summary of the changes and the related issue. Please also
include relevant motivation and context.

Adds an optional display_order field to each payment handler in
payment_handlers. Businesses (merchants) can set an integer per handler
(lower = higher preference) to suggest how payment methods should be ordered
when presented to the user. The ordering is suggestive only: platforms and
agents MAY reorder (e.g. for user preference, localization, or A/B tests). Addresses #170

This gives merchants a standard way to express their preferred order—e.g. for
fraud vs. conversion trade-offs—without requiring agents to follow it strictly.
Aligns with the same capability in the Agentic Commerce Protocol (ACP).

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing
    functionality to not work as expected, including removal of schema files
    or fields
    )
  • Documentation update

Is this a Breaking Change or Removal?

N/A — optional additive field only.


Motivation and context

Today the ordering of payment methods on the platform or agent side is
unspecified. Merchants know what works best for their fraud/conversion
trade-off and should be able to suggest an order at the spec level.

Fixes/Addresses: #[issue number] (fill in the UCP issue number you created)


Example

Handler with display_order:

{
  "id": "processor_tokenizer_1234",
  "version": "2026-01-11",
  "spec": "https://example.com/ucp/handler",
  "schema": "https://example.com/ucp/handler/schema.json",
  "config": { "environment": "production", "business_id": "business_xyz_789" },
  "display_order": 0
}

Lower display_order = higher preference (e.g. show first). Omission means no
suggestion.


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
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Pull Request Title

Use Conventional Commits, e.g.:

feat: add optional display_order to payment handlers


Files changed

  • Schema: source/schemas/payment_handler.json — added optional
    display_order (integer) to base definition.
  • Docs: docs/specification/payment-handler-guide.md — added
    display_order to Business Schema example and a short description of the
    field.

Additional notes

  • Backward compatible: Optional field; existing implementations can ignore
    unknown properties. No breaking changes.
  • If this project regenerates TypeScript types from the JSON schemas (e.g. via
    a script that reads source/schemas), re-run the generator so
    display_order appears in the generated types.
  • Same capability is implemented in the Agentic Commerce Protocol (ACP); this
    keeps UCP and ACP aligned for merchant-suggested payment handler ordering.

@prasad-stripe prasad-stripe requested a review from a team February 13, 2026 17:36
@igrigorik igrigorik added the TC review Ready for TC review label Feb 19, 2026
@raginpirate
Copy link
Copy Markdown
Contributor

Gave feedback in the issue description, as higher-level alignment on the solution will help drive this PR shape ❤️ 🚀
#170 (comment)

Move display_order from handler level to available_instruments level per
feedback on Universal-Commerce-Protocol#170. Ordering is suggestive and relative across all instruments
across all handlers, allowing businesses to rank distinct payment paths
independently (e.g., card via Google Pay before card via direct entry).
Addresses Universal-Commerce-Protocol#170
@prasad-stripe prasad-stripe force-pushed the feat/payment-handler-display-order branch from ca0845f to 040e293 Compare April 7, 2026 20:37
@prasad-stripe prasad-stripe requested review from a team as code owners April 7, 2026 20:37
@prasad-stripe
Copy link
Copy Markdown
Author

Gave feedback in the issue description, as higher-level alignment on the solution will help drive this PR shape ❤️ 🚀 #170 (comment)

Thanks @raginpirate — great point about handlers not being 1:1 with payment methods.

I've updated PR #176 to move display_order from the handler level to available_instruments. It's now an optional integer on available_payment_instrument.json, relative across all instruments across all handlers in the response. This handles both use cases: ordering funding sources (card before bank) and ordering distinct payment paths (card via Google Pay before card via direct entry).

Kept it to a single layer (instruments only) to keep semantics simple — we can add handler-level ordering later if needed. Would appreciate another look on the PR when you get a chance.

Copy link
Copy Markdown

@kmcduffie kmcduffie left a comment

Choose a reason for hiding this comment

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

@prasad-stripe Thanks for the PR! A few questions in line.

user preference, localization, A/B tests, or other factors.
- Entries without `display_order` express no preference and **SHOULD** be
placed after entries that declare one.
- When multiple entries share the same `display_order` value, the platform
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

An alternative might be that the spec does not support duplicate values in a given payload.

I'd like to better understand the use case you're thinking of that's driving this modeling where there could be collisions?

placed after entries that declare one.
- When multiple entries share the same `display_order` value, the platform
determines their relative order.
- `display_order` participates in the `available_instruments` resolution flow:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This field shares the same name as the first field in this comment. Did you mean for this to be different than the display_order above?

},
"display_order": {
"type": "integer",
"description": "Business-suggested display priority for this instrument across all handlers. Lower values indicate higher preference. Ordering is suggestive; platforms MAY override based on user preference, localization, or other factors.",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I don't believe a handler will know of any other handlers. Can the display_order be across all handlers, or is more signaling the priority within the instruments returned by this handler?

@raginpirate
Copy link
Copy Markdown
Contributor

raginpirate commented Apr 14, 2026

fwiw this PR is great @prasad-stripe, I got to catch @igrigorik async for a moment on this and I think there might be a higher level abstraction here for how we generally offer ordering hints across UCP for arrays... we're thinking about this and will circle back, if you don't also come up with something 😄

TLDR; seems like this isn't just a payments concern!

@archrao
Copy link
Copy Markdown

archrao commented Apr 20, 2026

Adding some thoughts for discussion to provide ordering hints for arrays within UCP objects (like available_instruments, line_items, totals, etc.)

Option 1: Sibling _hints Object
This approach adds a new JSON object alongside the array, named by convention as [array_field_name]_hints.
"available_instruments": [
{ "id": "instr_card", "type": "card", "description": "Major credit/debit cards" },
{ "id": "instr_paypal", "type": "ewallet", "description": "Pay with PayPal" },
{ "id": "instr_bnpl_klarna", "type": "bnpl", "description": "Pay over time with Klarna" }
],
"available_instruments_hints": {
"item_ids": ["instr_card", "instr_paypal", "instr_bnpl_klarna"],
"order": [
"instr_card",
"instr_paypal",
"instr_bnpl_klarna"
]}
This option is clean but could increase payload.

Option 2: In-Item _display Hints
This approach adds a reserved _display object within each item of the array that needs hints.
"available_instruments": [
{
"id": "instr_card",
"type": "card",
"description": "Major credit/debit cards",
"_display": {
"order": 1
}
}]
This option is more payload efficient and hints are co-located with the item.

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.

5 participants