feat: add required_fields to available payment instruments#288
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. |
69a3cd0 to
de0b8e6
Compare
There was a problem hiding this comment.
I understand the motivation here, but I am concern that this solution is not scalable, especially for any new schema type to be introduced. I think the right solution is to leverage the .schema field in entity (ucp.json#/$defs/entity).
Before PR #49 , payment handlers had separate config_schema (URI) and instrument_schemas (array of URIs). PR #49 consolidated these into a single schema URI — but this was a simplification of the reference structure, not a reduction in capability. A single JSON Schema document can contain $defs covering all instrument types and their requirements. That said, I think the protocol's existing schema field is already capable of expressing everything required_fields is trying to express, and more.
Although, one can argue that the current schema in the entity (ucp.json#/$defs/entity) cannot really express its intention. I imagine people often assume that schema is only for the payment handler config. As an alternative to introducing required_fields, I think re introducing instrument_schema (just URI, not array though) could solve the problem. What do you think?
|
@alexpark20 thanks for taking time to do the review! The context on #49 is useful. I agree that While I think I could get behind this idea here's a couple additional thoughts for why the
To make it concrete — here's the Shopify card handler under each approach:
{
"id": "shopify.card",
"version": "2026-01-15",
"schema": "https://shopify.dev/ucp/card-payment-handler/2026-01-15/config.json",
"available_instruments": [{
"type": "card",
"constraints": { "brands": ["visa", "master", "american_express"] },
// business can vary the required fields without serving a different handler schema
"required_fields": ["credential.cvc"]
}]
}
// https://shopify.dev/ucp/card-payment-handler/2026-01-15/instrument-requirements.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"allOf": [
// need to pull this schema...
{ "$ref": "https://ucp.dev/schemas/shopping/types/card_payment_instrument.json" },
{
"properties": {
"credential": {
"allOf": [
// ... and this one to get the complete picture of the type refinement
{ "$ref": "https://ucp.dev/schemas/shopping/types/card_credential.json" },
// probably requires a different schema when using this handler definition
// where CVC isn't required or zip code IS required
{ "required": ["cvc"] }
]
}
}
}
]
}Again - I think either way could work and I'm still getting calibrated on what best serves the broader community but hopefully this helps flesh out a bit more of the motivation for the |
Enable payment handlers to declare which optional fields they require for payment processing via a new `required_fields` property on `available_payment_instrument.json`. Uses dot notation for nested properties (e.g., `credential.cvc`, `billing_address.postal_code`). This eliminates guesswork for agentic platforms — they can collect exactly the right fields before attempting tokenization, avoiding trial-and-error retries and unnecessary over-collection of buyer data.
de0b8e6 to
ba16c3e
Compare
Enhancement Proposal: Required Fields on Available Payment Instruments
Summary
PR #187 added
available_instrumentsto payment handlers, with each instrument declaring atypeand optionalconstraints. This proposal adds arequired_fieldsoptional property toavailable_payment_instrument.json— enabling handlers to declare which optional fields they require for payment processing.Type of change
Motivation
UCP payment instruments are composed of two layers: the instrument itself (
payment_instrument.json— definesbilling_address,display, etc.) and a nested credential (card_credential.json— definescvc,name,cryptogram, etc.). Many properties across both layers are optional at the protocol level but required by individual merchants and their PSPs. For example:credential.cvcviacard_credential.json) — optional in the schema, but most merchants require it for card-not-present transactionscredential.nameviacard_credential.json) — optional in the schema, but required by some PSPs (e.g., Adyen)credential.cryptogram,credential.eci_valueviacard_credential.json) — optional in the schema, but required by PSPs when processing network tokens for customer-initiated transactionsbilling_addressonpayment_instrument.json) — optional in the schema, but required by merchants who use Address Verification System (AVS) checks. Whether a merchant uses AVS varies by market:In the traditional web flow, the merchant's checkout form explicitly shows which fields to fill in. In the agentic flow, there is no form — the platform must guess which optional fields the merchant actually requires. This leads to:
Goals
available_payment_instrument.json(PR #187) as a typed optional propertyNon-Goals
Related Work
available_instrumentswithtypeandconstraintsto payment handlers. This proposal adds a sibling property toconstraints.required_fieldsmakes that explicit in the handler configuration.Detailed Design
Modified Schema: available_payment_instrument.json
Add
required_fieldsas an optional property alongside the existingtypeandconstraints:{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://ucp.dev/schemas/shopping/types/available_payment_instrument.json", "title": "Available Payment Instrument", "description": "An instrument type available from a payment handler with optional constraints.", "type": "object", "required": ["type"], "properties": { "type": { "type": "string", "description": "The instrument type identifier (e.g., 'card', 'gift_card'). References an instrument schema's type constant." }, "constraints": { "type": "object", "additionalProperties": true, "description": "Constraints on this instrument type. Structure depends on instrument type and active capabilities.", "minProperties": 1 }, "required_fields": { "type": "array", "items": { "type": "string" }, "description": "Optional fields from the instrument or credential schemas that this handler requires for payment processing. Uses dot notation for nested properties: credential fields use 'credential.' prefix (e.g., 'credential.cvc'), billing address subfields use 'billing_address.' prefix (e.g., 'billing_address.postal_code'). Top-level instrument fields use their property name directly (e.g., 'billing_address' for the full object).", "minItems": 1, "uniqueItems": true } } }Field names in
required_fieldsuse dot notation to reference nested properties. Credential fields are nested under thecredentialproperty on the instrument, so they use thecredential.prefix (e.g.,credential.cvc,credential.name). Billing address subfields use thebilling_address.prefix to reference individual properties frompostal_address.json(e.g.,billing_address.postal_code,billing_address.country_code). Requiringbilling_addresswithout a subfield suffix means the full billing address object is required. This matches the actual structure of the payment instrument object that the platform constructs.Resolution Flow
Per the Payment Handler Guide, the business resolves
available_instrumentsby intersecting the platform's capabilities with its own configuration. The resolvedavailable_instrumentsin theresponse_schemais authoritative — platforms MUST treat it as the definitive source.required_fieldsparticipates in this resolution naturally: the business includesrequired_fieldsin the resolvedavailable_instrumentsreturned in the response. The platform reads these requirements from the response and knows exactly which fields to collect from the user before constructing the instrument.Usage Examples
The simplest and most common case — a merchant that requires CVC for card payments:
{ "payment_handlers": [ { "id": "handler_merchant_psp", "available_instruments": [ { "type": "card", "required_fields": ["credential.cvc"] } ] } ] }A US merchant requiring CVC and postal code for AVS (postal-only AVS), also accepting network tokens:
{ "payment_handlers": [ { "id": "handler_merchant_stripe", "available_instruments": [ { "type": "card", "required_fields": ["credential.cvc", "billing_address.postal_code"] }, { "type": "card_network_token", "required_fields": ["credential.cryptogram", "credential.eci_value"] } ] } ] }The platform only needs to collect a ZIP/postal code — not a full street address — reducing friction for the user while still satisfying the merchant's AVS check.
A US merchant requiring CVC and full billing address (full AVS):
{ "payment_handlers": [ { "id": "handler_merchant_full_avs", "available_instruments": [ { "type": "card", "required_fields": ["credential.cvc", "billing_address"] } ] } ] }When
billing_addressis specified without a subfield suffix, the platform collects the full billing address object.An EU merchant with no AVS (relies on 3D Secure), requiring cardholder name:
{ "payment_handlers": [ { "id": "handler_merchant_adyen", "available_instruments": [ { "type": "card", "required_fields": ["credential.cvc", "credential.name"] }, { "type": "card_network_token", "required_fields": ["credential.cryptogram", "credential.eci_value", "credential.name"] } ] } ] }Design Rationale
available_payment_instrument.json(PR #187). Non-breaking change: handlers that don't declarerequired_fieldsbehave exactly as before.required_fieldsas a typed property on the schema (rather than a key inside the untypedconstraintsbag) provides schema validation and encourages consistent reuse across implementations. This preventsconstraintsfrom becoming a free-form structure that varies across protocol implementations.credential,billing_address). Dot notation (e.g.,credential.cvc,billing_address.postal_code) unambiguously identifies which layer and subfield is required. Specifying a top-level name without a suffix (e.g.,billing_address) means the full object is required.available_instrumentsand the response is authoritative.required_fieldsis included in the resolved response, so platforms read it at the same time they discover which instruments are available — no additional round-trip needed.Risks and Mitigations
credential.cvcis clearly a credential field,billing_address.postal_codeis clearly a billing address subfield, andbilling_addresswithout a suffix means the full object. This mirrors the actual structure of the payment instrument object.Test Plan
required_fieldsaccepted onavailable_payment_instrument.jsonavailable_instrumentsworks normally withoutrequired_fields(non-breaking)required_fieldsforcard,card_network_token, andlinked_walletinstrument typesuniqueItems: verify duplicate field names are rejectedGraduation Criteria
Code Changes
Modified Files:
source/schemas/shopping/types/available_payment_instrument.json— add optionalrequired_fieldspropertydocs/specification/payment-handler-guide.md— Required Fields section, dot notation reference, usage examples, resolution flow integrationDiscussion Points:
billing_addressand subfield-level requirements (e.g.,billing_address.postal_code) using the same dot notation pattern as credential fields. This enables handlers to express postal-only AVS without requiring agents to collect a full street address. The subfield names reference properties frompostal_address.json. An open question is whether the protocol should define a recommended set of billing address subfields (e.g.,postal_code,country_code,street_address,locality,region) or leave it fully open to whateverpostal_address.jsondefines.References
available_payment_instrument.json— instrument type schema withtypeandconstraints(source)card_payment_instrument.json— extends base withavailable_card_payment_instrumentandconstraints.brands(source)payment_handler.json— payment handler schema withavailable_instrumentspayment_instrument.json— base instrument schema definingbilling_addresscard_credential.json— card credential schema definingcvc,name,cryptogram,eci_valueavailable_instrumentswith type-specific constraints to payment handlers (merged)Checklist