diff --git a/docs/specification/checkout-rest.md b/docs/specification/checkout-rest.md index 6524f0f5..71f1266e 100644 --- a/docs/specification/checkout-rest.md +++ b/docs/specification/checkout-rest.md @@ -703,6 +703,230 @@ Follow-up calls after initial `fulfillment` data to update selection. } ``` +#### 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. + +=== "Request" + + ```json + PUT /checkout-sessions/{id} HTTP/1.1 + UCP-Agent: profile="https://platform.example/profile" + Content-Type: application/json + + { + "id": "chk_123456789", + "buyer": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "line_items": [ + { + "item": { + "id": "item_123", + "title": "Red T-Shirt", + "price": 2500 + }, + "id": "li_1", + "quantity": 2 + } + ], + "fulfillment": { + "methods": [ + { + "id": "shipping_1", + "type": "shipping", + "line_item_ids": ["item_123"], + "selected_destination_id": "dest_home", + "destinations": [ + { + "id": "dest_home", + "street_address": "123 Main St", + "address_locality": "Springfield", + "address_region": "IL", + "postal_code": "62701", + "address_country": "US" + } + ], + "groups": [ + { + "id": "package_1", + "selected_option_id": "express" + } + ] + } + ] + }, + "payment": { + "instruments": [ + { + "id": "pi_gpay_5678", + "handler_id": "gpay_1234", + "type": "card", + "selected": true, + "display": { + "brand": "mastercard", + "last_digits": "5678", + "rich_text_description": "Google Pay •••• 5678" + }, + "eligibility_hints": [ + "com.example.tender_a" + ] + } + ] + } + } + ``` + +=== "Response" + + ```json + HTTP/1.1 200 OK + Content-Type: application/json + + { + "ucp": { + "version": "2026-01-11", + "capabilities": { + "dev.ucp.shopping.checkout": [ + {"version": "2026-01-11"} + ] + }, + "payment_handlers": { + "com.google.pay": [ + { + "id": "gpay_1234", + "version": "2026-01-11", + "config": { + "allowed_payment_methods": [ + { + "type": "CARD", + "parameters": { + "allowed_card_networks": ["VISA", "MASTERCARD", "AMEX"] + } + } + ] + } + } + ] + } + }, + "id": "chk_123456789", + "status": "ready_for_complete", + "currency": "USD", + "line_items": [ + { + "id": "li_1", + "item": { + "id": "item_123", + "title": "Red T-Shirt", + "price": 2500 + }, + "quantity": 2, + "totals": [ + {"type": "subtotal", "amount": 5000}, + {"type": "total", "amount": 5000} + ] + } + ], + "buyer": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "totals": [ + { + "type": "subtotal", + "amount": 5000 + }, + { + "type": "tax", + "amount": 400 + }, + { + "type": "total", + "amount": 5400 + } + ], + "links": [ + { + "type": "terms_of_service", + "url": "https://merchant.com/terms" + } + ], + "fulfillment": { + "methods": [ + { + "id": "shipping_1", + "type": "shipping", + "line_item_ids": ["item_123"], + "selected_destination_id": "dest_home", + "destinations": [ + { + "id": "dest_home", + "street_address": "123 Main St", + "address_locality": "Springfield", + "address_region": "IL", + "postal_code": "62701", + "address_country": "US" + } + ], + "groups": [ + { + "id": "package_1", + "line_item_ids": ["item_123"], + "selected_option_id": "express", + "options": [ + { + "id": "standard", + "title": "Standard Shipping", + "description": "Arrives in 5-7 business days", + "totals": [ + { + "type": "total", + "amount": 500 + } + ] + }, + { + "id": "express", + "title": "Express Shipping", + "description": "Arrives in 2-3 business days", + "totals": [ + { + "type": "total", + "amount": 1000 + } + ] + } + ] + } + ] + } + ] + }, + "payment": { + "instruments": [ + { + "id": "pi_gpay_5678", + "handler_id": "gpay_1234", + "type": "card", + "selected": true, + "display": { + "brand": "mastercard", + "last_digits": "5678", + "rich_text_description": "Google Pay •••• 5678" + }, + "eligibility_hints": [ + "com.example.tender_a" + ] + } + ] + } + } + ``` + ### Complete Checkout If businesses have specific logic to enforce field existence in `buyer` and @@ -730,6 +954,9 @@ place to set these expectations via `messages`. "card_art": "https://cart-art-1.html", "description": "Google Pay •••• 5678" }, + "eligibility_hints": [ + "com.example.tender_a" + ], "billing_address": { "street_address": "123 Main St", "address_locality": "Anytown", @@ -892,7 +1119,10 @@ place to set these expectations via `messages`. "brand": "mastercard", "last_digits": "5678", "rich_text_description": "Google Pay •••• 5678" - } + }, + "eligibility_hints": [ + "com.example.tender_a" + ] } ] } diff --git a/docs/specification/checkout.md b/docs/specification/checkout.md index a845eb59..9ca602e1 100644 --- a/docs/specification/checkout.md +++ b/docs/specification/checkout.md @@ -199,12 +199,13 @@ ELSE IF requires_buyer_review is not empty Standard errors are standardized error codes that platforms are expected to handle with specific, appropriate UX rather than generic error treatment. -| Code | Description | -| :----------------------- | :------------------------------------------------------------------------- | -| `out_of_stock` | Specific item or variant is unavailable | -| `item_unavailable` | Item cannot be purchased (e.g. delisted) | -| `address_undeliverable` | Cannot deliver to the provided address | -| `payment_failed` | Payment processing failed | +| Code | Description | +|:---------------------------|:------------------------------------------------------| +| `out_of_stock` | Specific item or variant is unavailable | +| `item_unavailable` | Item cannot be purchased \(e\.g\. delisted\) | +| `address_undeliverable` | Cannot deliver to the provided address | +| `payment_failed` | Payment processing failed | +| `invalid_eligibility_hint` | Submitted payment is not eligible for hinted benefits | Businesses **SHOULD** mark standard errors with `severity: recoverable` to signal that platforms should provide appropriate UX (out-of-stock messaging, diff --git a/docs/specification/overview.md b/docs/specification/overview.md index 08cebef9..f9c5ee47 100644 --- a/docs/specification/overview.md +++ b/docs/specification/overview.md @@ -1050,6 +1050,34 @@ within UCP: **Negotiation**, **Acquisition**, and **Completion**. 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 Eligibility Hints + +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. + +**Example Benefits:** + +- Co-branded Card Perks (e.g., instant discounts for using a specific brand's card). +- Issuer-Funded Promotions (e.g., statement credits). +- FX Fee Waivers for international transactions. +- Promotional APRs or specialized financing terms. +- Logistical Upgrades (e.g., expedited shipping for premium cardholders). + +Payment instruments **MAY** include an `eligibility_hints` array: opaque, namespaced strings that hint benefit eligibility associated with the selected instrument. The meaning of `eligibility_hints` 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). + +**eligibility_hints Strings:** + +- `eligibility_hints` strings **SHOULD** use reverse-domain naming to avoid collisions. +- `eligibility_hints` strings **MUST NOT** contain sensitive payment attributes such as PAN, BIN, PII, or user-unique identifiers. +- `eligibility_hints` strings **SHOULD** be coarse-grained program identifiers. + +**eligibility_hints Semantics:** + +- `eligibility_hints` are hints and **MUST NOT** be treated as proof of eligibility. +- The Business **MUST NOT** grant final or irreversible benefits solely due to `eligibility_hints`. +- The Business **MUST** determine benefits eligibility from the completion payment instrument and credential, not from `eligibility_hints`. +- The Business **SHOULD** return an error, using the [`invalid_eligibility_hint`](checkout.md#standard-errors), during checkout completion if the provided `eligibility_hints` do not match the final payment instrument's eligibility. +- When receiving `invalid_eligibility_hint`, the Platform **SHOULD** update `eligibility_hints`, and **MUST** present the user with an opportunity to review benefits changes (e.g. discounts, totals, etc.). + ### Payment Handlers Payment Handlers are **specifications** (not entities) that define how payment diff --git a/source/schemas/shopping/types/error_code.json b/source/schemas/shopping/types/error_code.json index 77ddf32d..4cc82b99 100644 --- a/source/schemas/shopping/types/error_code.json +++ b/source/schemas/shopping/types/error_code.json @@ -8,6 +8,7 @@ "out_of_stock", "item_unavailable", "address_undeliverable", - "payment_failed" + "payment_failed", + "invalid_eligibility_hint" ] } diff --git a/source/schemas/shopping/types/payment_instrument.json b/source/schemas/shopping/types/payment_instrument.json index aed22730..b12d8385 100644 --- a/source/schemas/shopping/types/payment_instrument.json +++ b/source/schemas/shopping/types/payment_instrument.json @@ -32,6 +32,15 @@ "display": { "type": "object", "description": "Display information for this payment instrument. Each payment instrument schema defines its specific display properties, as outlined by the payment handler." + }, + "eligibility_hints": { + "type": "array", + "description": "Opaque, namespaced eligibility hint strings from the Platform that hint to the Business the benefits to apply at checkout time, based on the selected payment instrument.", + "uniqueItems": true, + "items": { + "type": "string", + "maxLength": 256 + } } }, "additionalProperties": true,