Documentation Index Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
Use this file to discover all available pages before exploring further.
Discount Functions
Discount functions allow your app to apply custom discounts during checkout. Use them for tiered pricing, loyalty rewards, dynamic promotions, BOGO offers, and complex discount rules that go beyond standard discount codes.
How It Works
Function Manifest
{
"handle" : "my-discounts-app" ,
"name" : "Smart Discounts" ,
"version" : "1.0.0" ,
"functions" : {
"discount" : {
"handle" : "dynamic-discounts" ,
"name" : "Dynamic Discount Rules" ,
"config" : {
"vipDiscount" : 0.15 ,
"bulkThreshold" : 10 ,
"bulkDiscount" : 0.10
}
}
}
}
interface DiscountInput {
cart : {
items : CartItem [];
subtotal : number ;
currency : string ;
discountCodes : string []; // Customer-entered codes
attributes : Record < string , string >;
};
customer : {
id : string ;
email : string ;
tags : string [];
ordersCount : number ;
totalSpent : number ;
} | null ;
shop : {
id : string ;
currency : string ;
};
}
interface CartItem {
id : string ;
variantId : string ;
productId : string ;
title : string ;
quantity : number ;
price : number ; // Unit price in cents
sku : string ;
productType : string ;
vendor : string ;
tags : string [];
collections : string []; // Collection handles
properties : Record < string , string >;
}
Output Schema
interface DiscountOutput {
discounts : Discount [];
}
type Discount =
| {
type : 'percentage' ;
value : number ; // 0.0 to 1.0 (e.g., 0.15 = 15%)
target : DiscountTarget ;
message : string ; // Shown to customer
}
| {
type : 'fixed_amount' ;
value : number ; // Amount in cents
target : DiscountTarget ;
message : string ;
}
| {
type : 'buy_x_get_y' ;
buyQuantity : number ;
getQuantity : number ;
target : DiscountTarget ;
message : string ;
};
type DiscountTarget =
| { scope : 'all' } // All items
| { scope : 'product' ; productIds : string [] } // Specific products
| { scope : 'variant' ; variantIds : string [] } // Specific variants
| { scope : 'collection' ; handles : string [] } // Products in collections
| { scope : 'shipping' }; // Shipping cost
Discount Types
Percentage Discount
{
discounts : [
{
type: 'percentage' ,
value: 0.15 , // 15% off
target: { scope: 'all' },
message: 'VIP Member: 15% off entire order'
}
]
}
Fixed Amount Discount
{
discounts : [
{
type: 'fixed_amount' ,
value: 1000 , // $10 off
target: { scope: 'all' },
message: 'Loyalty reward: $10 off'
}
]
}
Buy X Get Y
{
discounts : [
{
type: 'buy_x_get_y' ,
buyQuantity: 2 ,
getQuantity: 1 , // Buy 2 get 1 free
target: {
scope: 'collection' ,
handles: [ 'sale-items' ]
},
message: 'Buy 2 get 1 free on sale items!'
}
]
}
Example Implementations
VIP Customer Discounts
function calculateDiscounts ( input , config ) {
const discounts = [];
const { customer } = input ;
if ( ! customer ) return { discounts };
// VIP tier discounts
const vipTiers = {
'vip_platinum' : { discount: 0.20 , name: 'Platinum' },
'vip_gold' : { discount: 0.15 , name: 'Gold' },
'vip_silver' : { discount: 0.10 , name: 'Silver' }
};
for ( const [ tag , tier ] of Object . entries ( vipTiers )) {
if ( customer . tags . includes ( tag )) {
discounts . push ({
type: 'percentage' ,
value: tier . discount ,
target: { scope: 'all' },
message: ` ${ tier . name } Member: ${ tier . discount * 100 } % off`
});
break ; // Only apply highest tier
}
}
return { discounts };
}
Tiered Spending Discounts
function calculateDiscounts ( input , config ) {
const discounts = [];
const { cart } = input ;
// Spend more, save more
const tiers = [
{ threshold: 20000 , discount: 0.20 , label: 'Spend $200+, save 20%' },
{ threshold: 15000 , discount: 0.15 , label: 'Spend $150+, save 15%' },
{ threshold: 10000 , discount: 0.10 , label: 'Spend $100+, save 10%' },
{ threshold: 5000 , discount: 0.05 , label: 'Spend $50+, save 5%' }
];
// Find applicable tier (highest first)
const applicableTier = tiers . find (
tier => cart . subtotal >= tier . threshold
);
if ( applicableTier ) {
discounts . push ({
type: 'percentage' ,
value: applicableTier . discount ,
target: { scope: 'all' },
message: applicableTier . label
});
}
return { discounts };
}
Buy X Get Y Free
function calculateDiscounts ( input , config ) {
const discounts = [];
const { cart } = input ;
// Buy 2 get 1 free on specific collection
const bogoCollections = [ 'tshirts' , 'accessories' ];
const bogoItems = cart . items . filter (
item => item . collections . some ( c => bogoCollections . includes ( c ))
);
const totalBogoQuantity = bogoItems . reduce (
( sum , item ) => sum + item . quantity , 0
);
// Every 3rd item is free
if ( totalBogoQuantity >= 3 ) {
discounts . push ({
type: 'buy_x_get_y' ,
buyQuantity: 2 ,
getQuantity: 1 ,
target: { scope: 'collection' , handles: bogoCollections },
message: 'Buy 2 Get 1 Free on T-Shirts & Accessories!'
});
}
return { discounts };
}
First Order Discount
function calculateDiscounts ( input , config ) {
const discounts = [];
const { customer , cart } = input ;
// New customer discount
if ( customer && customer . ordersCount === 0 ) {
discounts . push ({
type: 'percentage' ,
value: 0.10 ,
target: { scope: 'all' },
message: 'Welcome! 10% off your first order'
});
}
// Winback discount for returning customers
if ( customer && customer . ordersCount > 0 ) {
// Check if customer has been inactive (this would need date data)
// For demo, check a tag
if ( customer . tags . includes ( 'winback-eligible' )) {
discounts . push ({
type: 'fixed_amount' ,
value: 1500 ,
target: { scope: 'all' },
message: 'We missed you! $15 off your return order'
});
}
}
return { discounts };
}
Bundle Discount
function calculateDiscounts ( input , config ) {
const discounts = [];
const { cart } = input ;
// Define bundles and their discounts
const bundles = [
{
name: 'Complete Set' ,
requiredProducts: [ 'prod_shirt' , 'prod_pants' , 'prod_belt' ],
discount: 0.25
},
{
name: 'Starter Kit' ,
requiredProducts: [ 'prod_cleanser' , 'prod_moisturizer' ],
discount: 0.15
}
];
for ( const bundle of bundles ) {
const hasAllProducts = bundle . requiredProducts . every (
prodId => cart . items . some ( item => item . productId === prodId )
);
if ( hasAllProducts ) {
discounts . push ({
type: 'percentage' ,
value: bundle . discount ,
target: {
scope: 'product' ,
productIds: bundle . requiredProducts
},
message: ` ${ bundle . name } : ${ bundle . discount * 100 } % off when bought together`
});
}
}
return { discounts };
}
Category-Specific Discounts
function calculateDiscounts ( input , config ) {
const discounts = [];
const { cart } = input ;
// Sale collection
const saleItems = cart . items . filter (
item => item . collections . includes ( 'sale' )
);
if ( saleItems . length > 0 ) {
discounts . push ({
type: 'percentage' ,
value: 0.30 ,
target: { scope: 'collection' , handles: [ 'sale' ] },
message: 'Sale: 30% off clearance items'
});
}
// Bulk discount on specific vendor
const vendorItems = cart . items . filter (
item => item . vendor === 'Premium Brand'
);
const vendorQuantity = vendorItems . reduce (
( sum , item ) => sum + item . quantity , 0
);
if ( vendorQuantity >= 5 ) {
discounts . push ({
type: 'percentage' ,
value: 0.10 ,
target: {
scope: 'product' ,
productIds: vendorItems . map ( i => i . productId )
},
message: 'Bulk discount: 10% off 5+ Premium Brand items'
});
}
return { discounts };
}
Free Shipping Threshold
function calculateDiscounts ( input , config ) {
const discounts = [];
const { cart } = input ;
const freeShippingThreshold = config . freeShippingThreshold || 5000 ;
if ( cart . subtotal >= freeShippingThreshold ) {
discounts . push ({
type: 'percentage' ,
value: 1.0 , // 100% off shipping
target: { scope: 'shipping' },
message: `Free shipping on orders over $ ${ freeShippingThreshold / 100 } `
});
}
return { discounts };
}
Time-Limited Discounts
function calculateDiscounts ( input , config ) {
const discounts = [];
const now = new Date ();
const hour = now . getHours ();
const dayOfWeek = now . getDay ();
// Happy hour: 4 PM - 6 PM
if ( hour >= 16 && hour < 18 ) {
discounts . push ({
type: 'percentage' ,
value: 0.10 ,
target: { scope: 'all' },
message: 'Happy Hour: 10% off (4-6 PM only!)'
});
}
// Weekend special
if ( dayOfWeek === 0 || dayOfWeek === 6 ) {
discounts . push ({
type: 'percentage' ,
value: 0.05 ,
target: { scope: 'all' },
message: 'Weekend Special: Extra 5% off'
});
}
// Flash sale (check config for active sales)
const activeSale = config . flashSales ?. find (
sale => new Date ( sale . startTime ) <= now && now <= new Date ( sale . endTime )
);
if ( activeSale ) {
discounts . push ({
type: 'percentage' ,
value: activeSale . discount ,
target: activeSale . target ,
message: activeSale . message
});
}
return { discounts };
}
Cart Display
Discounts appear in the cart and checkout:
Your Cart
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Premium T-Shirt x 2 $59.98
Accessories Pack $29.99
Belt $24.99
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Subtotal $114.96
Applied Discounts:
✓ Complete Set: 25% off -$28.74
✓ Gold Member: 15% off -$12.93
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Total $73.29
You saved: $41.67
Discount Stacking
By default, your function’s discounts can stack with:
Discount codes entered by customers
Other app discount functions
Be careful with stacking. A 20% VIP discount + 30% sale + 10% code = 60% off total. Consider excluding already-discounted items.
Prevent Over-Discounting
function calculateDiscounts ( input , config ) {
const discounts = [];
const { cart } = input ;
// Don't stack with existing discount codes
if ( cart . discountCodes . length > 0 ) {
return { discounts }; // No additional discounts
}
// Or exclude sale items from VIP discount
const nonSaleItems = cart . items . filter (
item => ! item . collections . includes ( 'sale' )
);
if ( nonSaleItems . length > 0 ) {
discounts . push ({
type: 'percentage' ,
value: 0.15 ,
target: {
scope: 'product' ,
productIds: nonSaleItems . map ( i => i . productId )
},
message: 'VIP: 15% off (excludes sale items)'
});
}
return { discounts };
}
Best Practices
Messages appear in cart UI. Make them clear and concise: “VIP: 15% off” not “Discount applied based on customer tag vip_gold”.
Test with empty carts, single items, guest checkout, and various customer tiers.
Consider discount interactions
Think about how your discounts interact with store discount codes and other apps.
Discount functions run on cart updates. Keep calculations fast.
Log discount applications
Track which discounts are applied for reporting and debugging.
Store discount rules in config so you can update without code changes.
Testing
Test with various scenarios:
VIP Customer
First Order
Bundle Eligible
{
"cart" : {
"items" : [
{ "productId" : "prod_1" , "title" : "Widget" , "price" : 2999 , "quantity" : 2 }
],
"subtotal" : 5998 ,
"discountCodes" : []
},
"customer" : {
"id" : "cust_123" ,
"tags" : [ "vip_gold" ],
"ordersCount" : 10
}
}
See Also