feat: add payment instrument qualifiers#214
feat: add payment instrument qualifiers#214ACSchil wants to merge 10 commits intoUniversal-Commerce-Protocol:mainfrom
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
| Content-Type: application/json | ||
|
|
||
| { | ||
| "id": "chk_123456789", |
There was a problem hiding this comment.
The Update Payment example uses PUT /checkout-sessions/{id} and includes "id": "chk_123456789" in the body, but the spec section doesn’t state what happens if the path {id} and body id differ. Add a normative rule: either (a) body id MUST match path {id} and mismatches MUST be rejected with a specific error, or (b) body id is ignored and the path is authoritative.
There was a problem hiding this comment.
Great call-out. Because this PR feat did not introduce that potential conflict (i.e. there are other Update docs with this issue), I propose we create a separate issue to address that. Thoughts?
Thinking through the solution, it's probably to return a 400 or 422. And this would then be captured under https://ucp.dev/2026-01-23/specification/checkout-rest/#status-codes .
There was a problem hiding this comment.
Sounds good. Please create a separate issue.
| "type": "object", | ||
| "description": "Display information for this payment instrument. Each payment instrument schema defines its specific display properties, as outlined by the payment handler." | ||
| }, | ||
| "qualifiers": { |
There was a problem hiding this comment.
Qualifiers is currently an unbounded array of unbounded strings. For a protocol-level schema used by autonomous agents, this is a straightforward DoS / log-injection / storage-amplification risk.
Add schema constraints, for example:
- maxItems (e.g., 10–50 depending on expected use)
- uniqueItems: true (if semantics are set-like)
- string constraints like maxLength (e.g., 128/256) and a conservative pattern (e.g., reverse-domain-ish allowed chars)
Even if implementations don’t enforce strictly, having constraints in the canonical schema sets a safe baseline.
There was a problem hiding this comment.
How should we communicate the reverse-domain-ish characters?
Shall we say items match the pattern of ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+\.[a-z][a-z0-9_-]*$ ? i.e. {reverse-domain}.{service}.{qualifier}, e.g. "com.target.red_card" or "co.uk.example.qualifier-abc123"
There was a problem hiding this comment.
re: max items and string constraints; I feel like those needs to be applied across the board to UCP and are not today. We should discuss this in the TC; do we need a sweeping application of that to the spec, and should that be done in isolation of this PR?
I also disagree with enforcing reverse-dns here; from my POV the primary use case of this should be in-band by payment handlers to express how you negotiate qualfiier context that you want exposed by a payment handler for a specific instrument. Out-of-band use cases should not be dictated and require reverse-dns; they have their own solutions for identifying the relying party they negotiated with and interpreting those fields independently for those parties.
There was a problem hiding this comment.
I agree we have an opportunity to apply these across the board. I am okay adding the constraint here (as I have done), or removing it an referencing this feedback in a new issue that takes a broader look.
Out-of-band use cases should not be dictated and require reverse-dns
Without reverse domain naming, there's a significant chance of collision. Imagine two entities with member_program; it would be helpful for the program named be tied to that program owner, e.g. com.target.member_program so that another merchant can also have com.merchant_b.member_program.
…nstrument qualifiers
raginpirate
left a comment
There was a problem hiding this comment.
Thanks for driving at this! Sadly I missed our breakout on this topic last week, but I did add context to the notes about how I think we can introduce this ontop of #187.
I'm wondering why this PR doesn't have any approach for businesses to communicate the qualifiers they are asking from handlers and platforms.
| "type": "object", | ||
| "description": "Display information for this payment instrument. Each payment instrument schema defines its specific display properties, as outlined by the payment handler." | ||
| }, | ||
| "qualifiers": { |
There was a problem hiding this comment.
re: max items and string constraints; I feel like those needs to be applied across the board to UCP and are not today. We should discuss this in the TC; do we need a sweeping application of that to the spec, and should that be done in isolation of this PR?
I also disagree with enforcing reverse-dns here; from my POV the primary use case of this should be in-band by payment handlers to express how you negotiate qualfiier context that you want exposed by a payment handler for a specific instrument. Out-of-band use cases should not be dictated and require reverse-dns; they have their own solutions for identifying the relying party they negotiated with and interpreting those fields independently for those parties.
| }, | ||
| "qualifiers": { | ||
| "type": "array", | ||
| "description": "Opaque, namespaced qualifier strings from the Platform that hint to the Business the benefits to apply at checkout time, based on the selected payment instrument." |
There was a problem hiding this comment.
Will this always come from the platform?
Lets chat out a hypothetical.
I'm using , and using it's agentic mode it returns back to the platform a token encrypted for merchant 1234. As the platform, I have no ability to actually determine the qualifiers; that credential isn't transparent to me.
But, if the wallet exposes the selected instrument qualifier, then easy; we can pass it through to the merchant early, just like a shipping option event.
There was a problem hiding this comment.
we can pass it through to the merchant early
This comes from the Platform, correct? Even if the Platform is using a wallet that abstract the credential?
|
|
||
| #### Update Payment | ||
|
|
||
| Prior to completing checkout, the Platform may provide the Business with selected payment instrument hints. These hints allow the Business to apply to the checkout session the expected benefits the selected payment instrument qualifies the Buyer for. |
There was a problem hiding this comment.
I think we should come at this explanation as a feature of payment handlers, NOT from the perspective of a black hole platforms can leverage for out-of-band solutions.
As in, my payment handler lets me negotiate available qualifiers, and exposes that context to the agent to submit to the platform. It just so happens to give platforms and businesses an easy path to do out-of-band context sharing, but IMO we shouldn't be authoring this from that perspective.
There was a problem hiding this comment.
I understand this POV. See #214 (comment) . Are you okay with us moving forward with this for now?
docs/specification/overview.md
Outdated
| 2. **Acquisition (Platform ↔ Payment Credential Provider):** The platform executes the handler's logic. This happens client-side or agent-side, directly with the payment credential provider (e.g., exchanging credentials for a network token). The business is not involved, ensuring raw data never touches the business's frontend API. | ||
| 3. **Completion (Platform → Business):** The platform submits the opaque credential (token) to the business. The business uses it to capture funds via their backend integration with the payment credential provider. | ||
|
|
||
| ### Payment Qualifiers |
There was a problem hiding this comment.
Consideration: Is qualifiers descriptive enough? "Qualifiers" often implies a binding state or a restrictive limitation. Since the semantics explicitly define these as non-binding "hints" that require independent verification, benefit_hints or eligibility_hints might be a better fit. It signals that the field is a suggestion for the presentation and pre-checkout logic rather than a final, validated qualification for financial settlement.
docs/specification/overview.md
Outdated
| **Qualifier Strings:** | ||
|
|
||
| - Qualifier strings **SHOULD** use reverse-domain naming to avoid collisions. | ||
| - Qualifiers strings **MUST NOT** contain sensitive payment attributes such as PAN, BIN, PII, or user-unique identifiers. |
There was a problem hiding this comment.
Nit: We are not at all consistent, but define acronyms like BIN (Bank Identification Number)upon their first mention? It helps ensure the spec remains accessible to engineers who might be new to the payments domain.
There was a problem hiding this comment.
I agree. We have a glossary, but it's mostly for our own terms. Maybe separately we take a pass at capturing all acronyms there?
docs/specification/overview.md
Outdated
|
|
||
| Prior to completing checkout, the Platform **MAY** provide the Business with selected payment instrument *hints*. These hints allow the Business to apply to the checkout session the expected benefits the selected payment instrument qualifies the Buyer for. This gives the user a more accurate preview of the final order total before they commit to the purchase. | ||
|
|
||
| Payment instruments **MAY** include a `qualifiers` array: opaque, namespaced strings that hint benefit eligibility associated with the selected instrument. The meaning of qualifier values, and how they are derived, is communicated between the Business and Platform out of band (for example, via offline agreement on BIN ranges or program identifiers). |
There was a problem hiding this comment.
Consideration: Will this field exclusively be used for "benefits"?
While the current description focuses on perks like discounts, there are several
scenarios where a Platform might pass hints for regulatory or technical restriction
that aren't "benefits" to the user. For example:
- Product-Category Restrictions: Signaling a corporate or government card that is legally barred from purchasing specific items (e.g., alcohol, tobacco, or gaming).
- Surcharge Eligibility: Signaling a high-cost commercial card where a merchant is legally allowed (or required) to pass on a processing fee.
- KYC/Identity Status: Signaling a specific "Know Your Customer" verification level that might skip—or trigger—additional identity checks.
- Cross-Border Compliance: Signaling an instrument with geographic limitations that might affect tax or shipping legality.
If we anticipate these non-benefit use cases, would a more neutral term like eligibility_hints be more appropriate?
There was a problem hiding this comment.
Thanks for this input. I went with eligibility_hints.
@raginpirate , thank you for the notes! I agree that I believe we'll want to solve for communicating qualifiers. The consensus was that we did not want to prematurely prescribe how this is done, and that we will let usage inform next steps. Here's that decision - https://github.com/Universal-Commerce-Protocol/meeting-minutes/blob/main/tc/2026/2026-02-11.md?plain=1#L38 |
|
The trust question here — how does a Business verify that an We serve UCP-format eligibility checks across 31 blockchains. A Platform verifies a buyer's on-chain holdings with a single call: curl -X POST https://api.insumermodel.com/v1/ucp/discount \
-H "X-API-Key: insr_live_..." \
-H "Content-Type: application/json" \
-d '{"merchantId": "MERCHANT_ID", "wallet": "0xBuyerWallet..."}'The response is UCP-format ( Concretely: this lets a Platform turn an on-chain eligibility check into a cryptographically backed We already publish a UCP discovery file at |
Description
Context / Closes #137
Adds an optional qualifiers: string[] field to the Payment Instrument schema and documents Payment Qualifiers in the Checkout overview. Qualifiers are opaque, reverse-domain namespaced hints whose meaning/derivation is agreed out-of-band between the Platform and Business, enabling the Business to apply expected benefits prior to completion. If benefits are applied based on qualifiers, the Business SHOULD fail checkout when the selected payment instrument at completion does not meet the hinted qualifications; unknown qualifiers are treated as no-ops.
Type of change
Please delete options that are not relevant.
Is this a Breaking Change or Removal?
No. Adds a new optional field.
Checklist