Discount Extension
Discount Extension
Section titled “Discount Extension”Overview
Section titled “Overview”Discount extension allows businesses to indicate that they support discount codes on cart and checkout sessions, and specifies how the discount codes are to be shared between the platform and the business.
Key features:
- Submit one or more discount codes
- Receive applied discounts with human-readable titles and amounts
- Rejected codes communicated via
messages[]with detailed error codes - Automatic discounts surfaced alongside code-based discounts
Dependencies:
- Cart Capability or Checkout Capability
Discovery
Section titled “Discovery”Businesses advertise discount support in their profile. The capability can extend cart, checkout, or both:
{ "ucp": { "version": "2026-01-11", "capabilities": { "dev.ucp.shopping.discount": [ { "version": "2026-01-11", "extends": ["dev.ucp.shopping.cart", "dev.ucp.shopping.checkout"], "spec": "https://ucp.dev/2026-01-11/specification/discount", "schema": "https://ucp.dev/2026-01-11/schemas/shopping/discount.json" } ] } }}Businesses MAY advertise discount support for cart only, checkout only, or both. Platforms SHOULD check which resources are extended before submitting discount codes.
Schema
Section titled “Schema”When this capability is active, cart and/or checkout are extended with a
discounts object.
Discounts Object
Section titled “Discounts Object”| Field | Type | Description |
|---|---|---|
codes | array | Discount codes submitted by the platform |
applied | array | Applied discounts (code-based + automatic) |
Applied Discount
Section titled “Applied Discount”| Field | Type | Description |
|---|---|---|
code | string | The discount code (absent for automatic discounts) |
title | string | Human-readable discount name |
amount | integer | Discount amount in minor currency units |
method | string | Calculation method: each or across |
priority | integer | Application order (lower = applied first) |
automatic | boolean | True for automatically applied discounts |
allocations | array | Breakdown of where discount was applied |
Allocation
Section titled “Allocation”| Field | Type | Description |
|---|---|---|
path | string | JSONPath targeting the discounted resource |
amount | integer | Amount allocated to this target (minor currency units) |
Allocation Details
Section titled “Allocation Details”The applied array explains how discounts were calculated and distributed.
Allocation Method
Section titled “Allocation Method”The method field indicates how the discount was calculated:
| Method | Meaning | Example |
|---|---|---|
each | Applied independently per eligible item | ”10% off each item” → 10% × item price |
across | Split proportionally by value | ”$10 off order” → $6 to $60 item, $4 to $40 item |
Stacking Order
Section titled “Stacking Order”When multiple discounts are applied, priority indicates the calculation order.
Lower numbers are applied first:
Cart: $100Discount A (priority: 1): 20% off → $100 × 0.8 = $80Discount B (priority: 2): $10 off → $80 - $10 = $70Allocations Array
Section titled “Allocations Array”The allocations array breaks down where each discount dollar landed, using
JSONPath to identify targets:
| Path Pattern | Target |
|---|---|
$.line_items[0] | First line item |
$.line_items[1] | Second line item |
$.totals.shipping | Shipping cost |
Invariant: Sum of allocations[].amount equals applied_discount.amount.
Operations
Section titled “Operations”Discount codes are submitted via standard cart or checkout create/update operations. The same semantics apply to both resources.
Request behavior:
- Replacement semantics: Submitting
discounts.codesreplaces any previously submitted codes - Clear codes: Send empty array
"codes": []to remove all discount codes - Case-insensitive: Codes are matched case-insensitively by business
Response behavior:
discounts.appliedcontains all active discounts (code-based + automatic)- Rejected codes communicated via
messages[](see below) - Discount amounts reflected in
totals[]andline_items[].discount
Cart-to-checkout continuity: When a cart is converted to a checkout via the
cart capability’s cart_id field, businesses MUST carry forward any discount
codes that were applied to the cart. Codes that are no longer valid at checkout
time (e.g., expired, ineligible) SHOULD be communicated via messages[] using
standard rejection codes.
Rejected Codes
Section titled “Rejected Codes”When a submitted discount code cannot be applied, businesses communicate this
via the messages[] array:
{ "messages": [ { "type": "warning", "code": "discount_code_expired", "path": "$.discounts.codes[0]", "content": "Code 'SUMMER20' expired on December 1st" } ]}Implementation guidance: Operations that affect order totals, or the user’s expectation of the total, SHOULD use
type: "warning"to ensure they are surfaced to the user rather than silently handled by platforms. Rejected discounts are a prime example—the user expects a discount but won’t receive it, so they should be informed.
Error codes for rejected discounts:
| Code | Description |
|---|---|
discount_code_expired | Code has expired |
discount_code_invalid | Code not found or malformed |
discount_code_already_applied | Code is already applied |
discount_code_combination_disallowed | Cannot combine with another active discount |
discount_code_user_not_logged_in | Code requires authenticated user |
discount_code_user_ineligible | User does not meet eligibility criteria |
Automatic Discounts
Section titled “Automatic Discounts”Businesses may apply discounts automatically based on cart contents, customer segment, or promotional rules:
- Appear in
discounts.appliedwithautomatic: trueand nocodefield - Applied without platform action
- Cannot be removed by the platform
- Surfaced for transparency (platform can explain to user why discount was applied)
Impact on Line Items and Totals
Section titled “Impact on Line Items and Totals”Applied discounts are reflected in the core cart or checkout fields using two distinct total types:
| Total Type | When to Use |
|---|---|
items_discount | Discounts allocated to line items ($.line_items[*]) |
discount | Order-level discounts (shipping, fees, flat order amount) |
Determining the type: If a discount has allocations pointing to line
items, it contributes to items_discount. Discounts without allocations, or
with allocations to shipping/fees, contribute to discount.
Amount convention: All discount amounts are positive integers in minor currency units. When presenting totals to users, display discount types as subtractive (e.g., ”-$13.99”).
Examples
Section titled “Examples”Cart with discount codes
Section titled “Cart with discount codes”=== “Request”
```json{ "line_items": [ { "item": { "id": "prod_1", "quantity": 2, "title": "T-Shirt", "price": 2000 } } ], "discounts": { "codes": ["SUMMER20"] }}```=== “Response”
```json{ "id": "cart_abc123", "line_items": [ { "id": "li_1", "totals": [ {"type": "subtotal", "amount": 4000}, {"type": "items_discount", "amount": 800}, {"type": "total", "amount": 3200} ] } ], "discounts": { "codes": ["SUMMER20"], "applied": [ { "code": "SUMMER20", "title": "Summer Sale 20% Off", "amount": 800, "method": "each", "allocations": [ {"path": "$.line_items[0]", "amount": 800} ] } ] }, "totals": [ {"type": "subtotal", "display_text": "Subtotal", "amount": 4000}, {"type": "items_discount", "display_text": "Item Discounts", "amount": 800}, {"type": "total", "display_text": "Estimated Total", "amount": 3200} ]}```Rejected discount code
Section titled “Rejected discount code”When a discount code cannot be applied, the rejection is communicated via the
messages[] array. The code still appears in discounts.codes (echoed back)
but not in discounts.applied.
=== “Response”
```json{ "discounts": { "codes": ["SAVE10", "EXPIRED50"], "applied": [ { "code": "SAVE10", "title": "$10 Off Your Order", "amount": 1000 } ] }, "messages": [ { "type": "warning", "code": "discount_code_expired", "path": "$.discounts.codes[1]", "content": "Code 'EXPIRED50' expired on December 1st" } ]}```