Discount Functions
Discount functions apply custom discounts during checkout — VIP tiering, loyalty rewards, dynamic promotions, free-shipping thresholds, and any rule that goes beyond fixed-code discounts. Each discount your function returns is persisted as its own line so the cart, checkout, order summary, and receipts all render the app-supplied label next to its amount.How It Works
The function runs at both cart verification (cart/checkout preview) and order placement so the totals you see in the cart match what gets persisted.Function Manifest
Input Schema
Prices are in display currency units, not minor units (cents). A
price: 19.99 means ₹19.99 / $19.99 — no division required.shippingAddress fields are empty strings until the customer completes
the address step at checkout — always handle the empty case. Once the address
is entered, the function re-runs with the full destination (including zip),
which enables location-aware logic such as ZIP/district-level sales-tax
adjustments for US stores.Output Schema
Your function returns an array of discount entries. Each entry has the same shape — no separatepercentage / fixed_amount types. The kind of discount
is set by valueType, and the scope is set by target + targetSelection.
value semantics
valueType | value interpretation | Cap |
|---|---|---|
fixed | Amount in display currency (e.g. 10 = ₹10) | Capped at the remaining base |
percentage | Whole percent (e.g. 15 = 15%) | Clamped to [0, 100] |
target semantics
target | Base reduced |
|---|---|
order | Full line-item subtotal |
line_item | Subtotal of lines in lineIds (or full subtotal if targetSelection: 'all') |
shipping | shippingPrice + shippingZonePrice |
target: 'order' and target: 'line_item' both surface as appDiscount
(and on the persisted order, as an appDiscounts[] entry).
target: 'shipping' surfaces as shippingDiscount (and shippingDiscounts[]).
Examples
Percentage off the whole order
Fixed amount off
Discount on specific lines
Free shipping above a threshold
Tiered spending discount
Multiple discounts in one call
A function can return as many entries as it likes — each renders as a separate row.How the backend uses your output
For everyDiscountEntry your function returns, the platform:
-
Computes
entryAmountin display currency, capped by the entry’s base (subtotal, line-set subtotal, or shipping). -
Subtracts
entryAmountfromfinalPrice(and proportionally fromshippingPrice/shippingZonePricefor shipping discounts). -
Appends an entry to
additionalFields.appDiscounts[](orshippingDiscounts[]): -
Updates the summed scalars
additionalFields.appDiscountandadditionalFields.shippingDiscountfor backwards compatibility.
How it renders in the UI
The customer-facing summary renders one row per discount entry, using the exactmessage you supplied:
appDiscount / shippingDiscount.
Stacking and ordering
- Multiple discount apps run in install order; their outputs are concatenated.
- Each entry’s base is independent — a percentage entry doesn’t see earlier reductions. If you need compounding, do it in a single function.
target: 'shipping'entries cap at the remaining shipping. Two free- shipping discounts won’t refund shipping twice.appDiscountis surfaced separately fromcouponDiscount— coupons entered manually by the customer continue to apply in addition to your function output.
Best Practices
Use clear, customer-facing `title` text
Use clear, customer-facing `title` text
The
title (or message, if you set it) shows up in the cart,
checkout, order page, and email receipt. Prefer “VIP: 15% off” over
“Discount applied based on tag vip_gold”.Return early on empty input
Return early on empty input
if (!input.customer) return { discounts: [] } keeps unauthenticated
carts fast.Keep `value` integer where possible
Keep `value` integer where possible
value: 15 for 15% is easier to debug than 0.15.Test against the real checkout
Test against the real checkout
The platform exposes cart-verification + order-placement parity — your
function output must produce the same totals on both sides. Run the
cart UI in a browser, not just the function’s JSON output, before
shipping.
Don't return zero-value entries
Don't return zero-value entries
Entries with
entryAmount capped to 0 are filtered out — they
wouldn’t render anyway.See Also
- Cart Transform Functions — per-line price
adjustments, bundles, merge/expand. Surfaces as
cartTransformDiscount. - Shipping Rate Functions — add new rates rather than discount an existing one.
- Order Validation Functions — block order placement based on cart contents.