This guide provides the technical API reference and payload schemas for handling
promotional codes and discounts in version 2026-04-08 of the Universal
Commerce Protocol (UCP).
Before building your endpoints, ensure you have reviewed the Promo codes and discounts overview for the high-level concepts, mathematical invariants, and error handling rules.
Discovery
To receive discount codes from Google, you must advertise discount support in
your profile. In version 2026-04-08, platforms check if the checkout
capability is extended before submitting discount codes.
{
"ucp": {
"version": "2026-04-08",
"capabilities": {
"dev.ucp.shopping.discount": [
{
"version": "2026-04-08",
"extends": ["dev.ucp.shopping.checkout"],
"spec": "https://ucp.dev/2026-04-08/specification/discount",
"schema": "https://ucp.dev/2026-04-08/schemas/shopping/discount.json"
}
]
}
}
}
Impact on line items and totals
Applied discounts are reflected in the core checkout fields using two distinct
total types. If a discount has allocations pointing to line items, it
contributes to items_discount. Discounts without allocations, or with
allocations to shipping or fees, contribute to discount.
| Discount type | Total type | Where reflected |
|---|---|---|
| Line-item discount | items_discount |
line_items[].totals[type=items_discount] |
| Order-level discount | discount |
totals[type=discount] |
Version requirement:
For version 2026-04-08, discount entries in totals[] and
line_items[].totals[] must use negative values to reflect their
subtractive effect on the receipt. Amounts inside the discounts.applied and
allocations arrays always remain positive integers.
API examples for auto-applied promotions
The following examples demonstrate discounts applied automatically. The request
payloads don't contain a discounts.codes array, but the responses include
"automatic": true and omit the code field.
Auto-applied item-level discount
A 10% sitewide sale automatically applied to a specific line item.
Request example:
{
"line_items": [
{
"id": "li_1",
"item": { "title": "Sneakers", "price": 10000 },
"quantity": 1
}
]
}
Response example:
{
"line_items": [
{
"id": "li_1",
"item": { "title": "Sneakers", "price": 10000 },
"quantity": 1,
"totals": [
{"type": "subtotal", "amount": 10000},
{"type": "items_discount", "amount": -1000},
{"type": "total", "amount": 9000}
]
}
],
"discounts": {
"applied": [
{
"title": "10% Off Sitewide Sale",
"amount": 1000,
"automatic": true,
"method": "each",
"allocations": [
{"path": "$.line_items[0]", "amount": 1000}
]
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 10000},
{"type": "items_discount", "display_text": "Item Discounts", "amount": -1000},
{"type": "total", "display_text": "Total", "amount": 9000}
]
}
Auto-applied order-level discount
A promotional rule (e.g., "$10 off orders over $50") applied to the order as a whole without specific line-item allocations.
Request example:
{
"line_items": [ ... ]
}
Response example:
{
"line_items": [ ... ],
"discounts": {
"applied": [
{
"title": "$10 Off Orders Over $50",
"amount": 1000,
"automatic": true
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 6000},
{"type": "discount", "display_text": "Order Promo", "amount": -1000},
{"type": "total", "display_text": "Total", "amount": 5000}
]
}
API examples for user-applied promotions
The following examples demonstrate discounts triggered by a user entering a promotional code. The request payloads include the requested codes, and the responses echo them back while allocating the applied amounts.
Order-level discount
A flat discount applied to the order total. No allocations are needed; the
discount applies to the order as a whole and uses type: "discount".
Request example:
{
"line_items": [ ... ],
"discounts": {
"codes": ["SAVE10"]
}
}
Response example:
{
"line_items": [ ... ],
"discounts": {
"codes": ["SAVE10"],
"applied": [
{
"code": "SAVE10",
"title": "$10 Off Your Order",
"amount": 1000
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 5000},
{"type": "discount", "display_text": "Order Discount", "amount": -1000},
{"type": "total", "display_text": "Total", "amount": 4000}
]
}
Mixed discounts (item + order level)
This example shows both discount types: a per-item discount (20% off) allocated to line items, and an automatic shipping discount at the order level.
Request example:
{
"line_items": [ ... ],
"discounts": {
"codes": ["SUMMER20"]
}
}
Response example:
{
"line_items": [
{
"id": "li_1",
"item": { "title": "T-Shirt", "price": 2000 },
"quantity": 2,
"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,
"allocations": [
{"path": "$.line_items[0]", "amount": 800}
]
},
{
"title": "Free shipping on orders over $30",
"amount": 599,
"automatic": true
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 4000},
{"type": "items_discount", "display_text": "Item Discounts", "amount": -800},
{"type": "discount", "display_text": "Order Discounts", "amount": -599},
{"type": "fulfillment", "display_text": "Shipping", "amount": 0},
{"type": "total", "display_text": "Total", "amount": 2601}
]
}
Rejected discount code
When a code is invalid, it is echoed in codes but omitted from applied. The
rejection is communicated using a warning in the messages[] array.
Request example:
{
"line_items": [ ... ],
"discounts": {
"codes": ["SAVE10", "EXPIRED50"]
}
}
Response example:
{
"line_items": [ ... ],
"discounts": {
"codes": ["SAVE10", "EXPIRED50"],
"applied": [
{
"code": "SAVE10",
"title": "$10 Off Your Order",
"amount": 1000
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 5000},
{"type": "discount", "display_text": "Order Discount", "amount": -1000},
{"type": "total", "display_text": "Total", "amount": 4000}
],
"messages": [
{
"type": "warning",
"code": "discount_code_expired",
"path": "$.discounts.codes[1]",
"content": "Code 'EXPIRED50' expired on December 1st"
}
]
}
Stacked discounts with allocations
Multiple discounts applied with full allocation breakdowns.
Request example:
{
"line_items": [ ... ],
"discounts": {
"codes": ["SUMMER20", "EXTRA5"]
}
}
Response example:
{
"line_items": [
{
"id": "li_1",
"item": { "title": "T-Shirt", "price": 6000 },
"quantity": 1,
"totals": [
{"type": "subtotal", "amount": 6000},
{"type": "items_discount", "amount": -1500},
{"type": "total", "amount": 4500}
]
},
{
"id": "li_2",
"item": { "title": "Socks", "price": 4000 },
"quantity": 1,
"totals": [
{"type": "subtotal", "amount": 4000},
{"type": "items_discount", "amount": -1000},
{"type": "total", "amount": 3000}
]
}
],
"discounts": {
"codes": ["SUMMER20", "EXTRA5"],
"applied": [
{
"code": "SUMMER20",
"title": "Summer Sale 20% Off",
"amount": 2000,
"method": "each",
"priority": 1,
"allocations": [
{"path": "$.line_items[0]", "amount": 1200},
{"path": "$.line_items[1]", "amount": 800}
]
},
{
"code": "EXTRA5",
"title": "Extra $5 Off",
"amount": 500,
"method": "across",
"priority": 2,
"allocations": [
{"path": "$.line_items[0]", "amount": 300},
{"path": "$.line_items[1]", "amount": 200}
]
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 10000},
{"type": "items_discount", "display_text": "Item Discounts", "amount": -2500},
{"type": "total", "display_text": "Total", "amount": 7500}
]
}