Discounts and Promotions
Build Any Discount Model
50min
high levelintroduction one of the core principles our system is built upon is having flexible data structures this schema is the means by which we can support any meter type, price machine, rewards algorithm, or discount you may want to apply this document is focused on the promotions model we will discuss the discount data structure the generic discount advanced, very flexible data structures the discount templates the more simplistic, but also more easily configurable data structures the discount structure generally speaking, a discount is made up of the following parts granularity condition discount model measure we will explain these notions in the next sections for the moment let's start by introducing a high level diagram for the promotion structure granularity in a usage based pricing world, an invoice contains many prices total invoice price (before discounts) the total usage price is the sum of all of the item prices > total price for a specific invoiced item individually is the sum of all of the variant prices > prices for each specific item variant usage individually (invoice for an item with specific dimension values) total fixed fee prices is the sum of all the fixed fees applied > price for each individual fee granularity is an object to let us specify the target of the discount currently we support the following granularities product (or plan) both discount the total invoice price item discount the total price for a specific invoiced item (ie a specific product item) down the line we may include additional granularities for example, a discount for the total usage price, or a discount on a specific fixed fee the important thing to remember , is that each part of the invoice can be a subject to a discount condition this part answers the following questions can we apply a discount? can we apply a discount to the customer or can we keep the current discount from the previous cycle can we use the discount at this time? even if we can apply a discount to a customer, it's still possible that we can't use it to discount the current invoice below is a diagram describing the existing discount conditions time limited condition this condition limits a discount for a certain amount of billing cycles, months or the min of both if neither 'cycles' or 'months' are provided, or if the 'promotiontimelimit' is not provided than there is no time limit to the discount schema \ type "object" properties requiredhistory type "object" properties cycles type "integer" description "max amount of billing cycles this promotion can be applied (optional)" months type "integer" description "max amount of months this promotion can be applied (optional)" type type "string" same plan condition a condition for keeping a discount as long as the customer is on same plan as the plan used when applying the discount schema \ type "object" properties type type "string" 	 description "must be same plan" after product price threshold condition this condition simply tells our system to start applying the discount to an account after the customer has met a certain predefined "product level bill threshold" this "threshold" is an accumulating sum of the total price of the current and previous invoice as specified in the 'requiredhistory' of the condition for example, this condition would allow for a discount which may be applied after the customer spends their first $1,000, regardless of how many billing cycles it takes to reach this threshold schema \ type "object" properties minthreshold type "number" requiredhistory type "object" properties cycles type "integer" months type "integer" type type "string" description "must be after product price threshold" after item price threshold condition this condition is very similar to the product level price threshold condition this condition looks at the total price of a specific product item , as opposed to the total price of the entire product usage schema \ type "object" properties minthreshold type "number" itemid type "string" requiredhistory type "object" properties cycles type "integer" months type "integer" type type "string" description "must be after item price threshold" next billing cycle this discount condition doesn't impose any condition for applying the discount instead, it tells our system to start using a discount on the next month from the moment it was assigned \ type "object" properties type type "string" no condition this special "condition" is just to serve as a placeholder for condition in cases where we don't wish to specify any schema \ type "object" properties type type "string" and condition the "and condition" is just a simple way to combine multiple conditions using an 'and' clause schema \ type "object" properties conditions type "array" items type "object" description "an array of condition objects" type type "string" description "must be and condition" discount model this is the actual discount model we apply on the current invoice we currently support the following models model with max this isn't a concrete model but rather a parent class of all of our existing models a "model with max" discount model comes with an optional total max discount (since the discount was applied) an optional billing cycle max discount absolute a constant discount for the entire bill (can be the product item or the entire product bill depending on the granularity) schema \ type "object" properties cyclemaxdiscount type "number" discount type "number" measure type "object" requiredhistory type "object" properties cycles type "integer" months type "integer" totalmaxdiscount type "number" type type "string" 	 description "must be and condition" relative the discount is a constant ratio of the total price (can be for a product item or the entire product bill depending on the granularity) schema \ type "object" properties cyclemaxdiscount type "number" discountratio type "number" measure type "object" requiredhistory type "object" properties cycles type "integer" months type "integer" totalmaxdiscount type "number" type type "string" tiered absolute this discount is similar to the absolute case, only in this case the discount amount is determined according to the total invoice price using some predefined discounting tiers schema \ type "object" properties cyclemaxdiscount type "number" discountvaluemap type "object" additionalproperties type "number" measure type "object" requiredhistory type "object" properties cycles type "integer" months type "integer" totalmaxdiscount type "number" type type "string" 	 description "must be price tiered absolute" example { "discountvaluemap" { "50" 1 "100" 10 }, "type" "price tiered absolute", "measure" { "type" "total price" }, "requiredhistory" { "cycles" 0, "months" 0 }, "totalmaxdiscount" null, "cyclemaxdiscount" null } the configuration above represents a tiered absolute discount of $1 for any total price between $50 to $100 $10 for any total price of $100 or higher tiered relative the tiered relative discount is more of a flexible case, and can actually contain the following two discounting algorithms choose single tier the discount amount is determined according to the total invoice price using some predefined tiers and applied to the entire discountable price step function this option can be thought of in the same way income tax amounts are calculated we split the total discountable price value into intervals (ranging from 0 to inf) where each interval starting point is marked as 'ai' and identify the interval then the total discount is total discount = sum over all ai s of max(0, min(ai+1 ai, price value ai)) discount ai schema \ type "object" properties cyclemaxdiscount type "number" discountcalculationstrategy type "string" description "step function, choose single tier" discountratiomap type "object" additionalproperties type "number" measure type "object" requiredhistory type "object" properties cycles type "integer" months type "integer" totalmaxdiscount type "number" type type "string" description "must be price tiered relative" for example, let's assume the following tiers now, for a price of $1050 with 'choose single tier' we will calculate a discount of 1050 0 06 = $63 discount with 'step function' we will calculate a discount of 100 0 00 + (1000 100) 0 05 + (1050 1000) 0 06 = 0 + 45 + 3 = $48 discount measure before moving forward to the different discount object types, let's cover one last (advanced object) the discount model itself can work on the price, but can also work on the usage using the average item price for each invoiced unit a batch of usage using the item p why do we need the measure imagine that you want to give an absolute discount for an item invoice an item invoice contains the the total amount of usage for the item the total price of the item usage now, here are the options for giving an absolute discount for an invoiced item totalprice a discount of $x for the entire bill (bill can be product item level or product level depending on the granularity) perunit a discount of $y for each invoiced unit of usage invoiced perunitbatch a discount of $z for each batch of n units of usage invoiced for example, you can give a $100 discount for the entire item bill, but you can also give, let's say $0 01 for each invoiced unit of usage schemas total price schema \ type "object" properties type type "string" 	 description "must be total price" per unit schema \ type "object" properties type type "string" 	 description "must be per unit" per unit batch schema \ type "object" properties batchsize type "integer" type type "string" description "must be per batch" generic discounts generic models are the most advanced data structure we have they are only available on the api and they allow you to create a specific discount if this isn't captured by any of the templates (mentioned below) as a rule of thumb, because generic discounts are more difficult to configure, we suggest you to first see if there is a template that fits your needs, and only if not consider using a generic promotions we currently support two types of generic models genericproductpromotion schema \ type "object" properties condition type "object" description type "string" id type "string" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" promotionmodel type "object" promotionname type "string" promotiontype type "string" description "only 'discount' is currently supported" default "discount" targetproductid type "string" type type "string" description "must be generic product promotion" example 1 below is an example for a product (granularity), time limited (condition), relative (discount model) discount please compare it with the example for "time limited relative product discount" below { "targetproductid" "ed7a3d38 bdd0 4db2 b047 2bc5d7b67336", "promotiontype" "discount", "condition" { "type" "time limited", "requiredhistory" { "cycles" 0, "months" 1 } }, "promotionmodel" { "discountratio" 0 1, "type" "relative", "measure" { "type" "total price" }, "requiredhistory" { "cycles" 0, "months" 1 }, "totalmaxdiscount" 100, "cyclemaxdiscount" 20 }, "id" "6aa33aa2 daf5 47b1 80c0 394127f383e7", "type" "generic product promotion", "promotionname" "55ed6c54 a201 4bfe aaba d9bd1b759d7c", "lockingstatus" "open" } example 2 a relative product level discount with the following conditions a total accumulating product price of $10 over the last 6 month (including current) a time limit of 18 months since the discount was first applied (naturally you are less likely to configure such a discount, what we wanted to convey with this example is the flexibility of this schema ) { "targetproductid" "392d5b67 f49d 43c9 979b 89b296063f79", "promotiontype" "discount", "condition" { "type" "and condition", "conditions" \[ { "type" "after product price threshold", "requiredhistory" { "cycles" 0, "months" 6 }, "minthreshold" 10 }, { "type" "time limited", "requiredhistory" { "cycles" 0, "months" 18 } } ] }, "promotionmodel" { "discountratio" 0 1, "type" "relative", "measure" { "type" "total price" }, "requiredhistory" { "cycles" 0, "months" 1 }, "totalmaxdiscount" 100, "cyclemaxdiscount" 20 }, "id" "36577499 d2d2 478d 974a 1f34bc7464e9", "type" "generic product promotion", "promotionname" "0a81c207 6232 4d08 88a1 e877a87c6d53", "description" null, "lockingstatus" "open", "lastupdatetimeinmillis" 0 } genericitempromotion schema \ type "object" properties condition type "object" description type "string" dimensionconstraintmap type "object" description "a map of dimension key to value (string to string) indicating that this promotion can only be applied against usage that includes the given dimension values " additionalproperties type "string" id type "string" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" promotionmodel type "object" promotionname type "string" promotiontype type "string" description "only 'discount' is currently supported" default "discount" targetitemid type "string" type type "string" description "must be generic item promotion" example 1 below is an example for an item (granularity), time limited (condition), relative (discount model) discount please compare it with the example for "time limited relative product discount" below { "targetitemid" "58e0a665 5244 4d01 8e1e c0a7a72f169a", "promotiontype" "discount", "condition" { "type" "time limited", "requiredhistory" { "cycles" 0, "months" 1 } }, "promotionmodel" { "discountratio" 0 1, "type" "relative", "measure" { "type" "total price" }, "requiredhistory" { "cycles" 0, "months" 1 }, "totalmaxdiscount" 100, "cyclemaxdiscount" 20 }, "id" "50aa986b d384 4dc4 8a9e eee1f29f46f5", "type" "generic item promotion", "promotionname" "1675182e 5837 48e7 8df2 41a81aa9815f", "lockingstatus" "open", "lastupdatetimeinmillis" 0 } example 2 below is an example for an item (granularity), time limited (condition), relative (discount model) discount exactly as in example 1 but we also added a constraint to it, that the discount can only be applied towards usage with the following dimension's values cloudprovider = aws region = us west 2 { "targetitemid" "58e0a665 5244 4d01 8e1e c0a7a72f169a", "promotiontype" "discount", "condition" { "type" "time limited", "requiredhistory" { "cycles" 0, "months" 1 } }, "dimensionconstraintmap" { "region" "us west 2", "cloudprovider" "aws" }, "promotionmodel" { "discountratio" 0 1, "type" "relative", "measure" { "type" "total price" }, "requiredhistory" { "cycles" 0, "months" 1 }, "totalmaxdiscount" 100, "cyclemaxdiscount" 20 }, "id" "50aa986b d384 4dc4 8a9e eee1f29f46f5", "type" "generic item promotion", "promotionname" "1675182e 5837 48e7 8df2 41a81aa9815f", "lockingstatus" "open", "lastupdatetimeinmillis" 0 } example 3 a relative item discount with the following conditions a total accumulating item price of $10 over the last 5 invoices (including current) a total accumulating product price of $500 over the last 5 invoices (including current) the plan wasn't changed since the discount has started a time limit of 12 months since the discount was first applied (naturally you are less likely to configure such a discount, what we wanted to convey with this example is the flexibility of the schema ) { "targetitemid" "ca288a7c 9944 41d4 a7e2 d47eabce1496", "promotiontype" "discount", "condition" { "type" "and condition", "conditions" \[ { "type" "after item price threshold", "itemid" null, "requiredhistory" { "cycles" 5, "months" 0 }, "minthreshold" 10 }, { "type" "after product price threshold", "requiredhistory" { "cycles" 5, "months" 0 }, "minthreshold" 500 }, { "type" "same plan" }, { "type" "time limited", "requiredhistory" { "cycles" 0, "months" 12 } } ] }, "promotionmodel" { "discountratio" 0 1, "type" "relative", "measure" { "type" "total price" }, "requiredhistory" { "cycles" 10, "months" null }, "totalmaxdiscount" 100, "cyclemaxdiscount" 20 }, "id" "f2aac76a 840a 4608 b268 bae52615e637", "type" "generic item promotion", "promotionname" "d6a2eb2a 91f5 407d bde9 2bfa2f1d6e7d", "description" null, "lockingstatus" "open", "lastupdatetimeinmillis" 0 } templates template are the most common forms of discounts we see; because they represent patterns of discounts that repeats themselves, we wrapped them in an easy to use configuration below is a list of the currently available templates time limited absolute product discount granularity product condition time limited discount model absolute schema \ type "object" properties description type "string" discount type "number" id type "string" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" promotionname type "string" promotiontimelimit type "object" properties cycles type "integer" months type "integer" targetproductid type "string" totalmaxdiscount type "number" type type "string" description "must be time limited absolute product discount" example in the example below we create a new discount which is limited to 12 months since the moment it is applied to a customer the discount itself targets the entire invoice bill, and it can give a discount of up to $25 per invoice, or up to $100 for all consecutive invoices since the discount was applied { "targetproductid" "4d228d9e 0683 4636 b21f 81c4127298dc", "promotiontimelimit" { "cycles" 0, "months" 12 }, "discount" 25, "totalmaxdiscount" 100, "id" "10de0900 7751 43f7 a415 fec4fa835009", "type" "time limited absolute product discount", "promotionname" "my promo", "lockingstatus" "open" } time limited absolute item discount granularity item condition time limited discount model absolute schema \ type "object" properties description type "string" dimensionconstraintmap type "object" additionalproperties type "string" discount type "number" id type "string" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" promotionname type "string" promotiontimelimit type "object" properties cycles type "integer" months type "integer" targetproductitemid type "string" totalmaxdiscount type "number" type type "string" description "must be time limited absolute item discount" example in the example below we create a new discount which is limited to 12 months since the moment it is applied to a customer the discount itself targets the entire invoice of a single item usage ("552a8bf2 864e 4f89 87b0 0962aaec5cdf"), and it can give a discount of up to $10 per invoice, or up to $50 for all consecutive invoices since the discount was applied { "targetproductitemid" "552a8bf2 864e 4f89 87b0 0962aaec5cdf", "promotiontimelimit" { "cycles" 0, "months" 12 }, "discount" 10, "totalmaxdiscount" 500, "id" "9d6cb505 bc9a 4ada 8f27 5b39a39428aa", "type" "time limited absolute item discount", "promotionname" "my promo", "lockingstatus" "open" } time limited relative product discount granularity product condition time limited discount model relative schema \ type "object" properties cyclemaxdiscount type "number" description type "string" discountratio type "number" id type "string" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" promotionname type "string" promotiontimelimit type "object" properties cycles type "integer" months type "integer" targetproductid type "string" totalmaxdiscount type "number" type type "string" description "must be time limited relative product discount" example in the example below we create a new discount which is limited to 18 billing cycles since the moment it is applied to a customer the discount itself gives a 10% discount on the top of the entire bill (up to $100 for all consecutive invoices since the discount was applied) { "targetproductid" "feb90ba8 58a5 4c93 862a 8befc88c31c7", "promotiontimelimit" { "cycles" 18, "months" 0 }, "discountratio" 0 1, "totalmaxdiscount" 100, "cyclemaxdiscount" null, "id" "db859149 56e5 4b35 8946 96efdff0c7f9", "type" "time limited relative product discount", "promotionname" "my promo", "lockingstatus" "open" } time limited relative item discount granularity item condition time limited discount model relative schema \ type "object" properties cyclemaxdiscount type "number" description type "string" dimensionconstraintmap type "object" description "a map of dimension key to value (string to string) indicating that this promotion can only be applied against usage that includes the given dimension values " additionalproperties type "string" discountratio type "number" id type "string" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" promotionname type "string" promotiontimelimit type "object" properties cycles type "integer" months type "integer" targetproductitemid type "string" totalmaxdiscount type "number" type type "string" description "must be time limited relative item discount" example in the example below we create a new discount which is limited to 18 billing cycles since the moment it is applied to a customer the discount itself gives a 10% discount on the top of the usage cost of item "acde888f 7720 4138 918d f9442febc96e" (and up to $100 for all consecutive invoices since the discount was applied) { "targetproductitemid" "acde888f 7720 4138 918d f9442febc96e", "promotiontimelimit" { "cycles" 18, "months" 0 }, "discountratio" 0 1, "totalmaxdiscount" 100, "cyclemaxdiscount" null, "id" "768dbdb4 932b 430b be8c aae3a9a2c1ca", "type" "time limited relative item discount", "promotionname" "my promo", "lockingstatus" "open" } time limited tiered absolute product discount granularity product condition time limited discount model tiered absolute schema \ type "object" properties acrossbillingperiods type "boolean" description "if true then the tier level discount will be detemined using the sum of all invoices since the promotion was applied " description type "string" discountmap type "object" 	 additionalproperties type "number" id type "string" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" measure type "object" promotionname type "string" promotiontimelimit type "object" properties cycles type "integer" months type "integer" targetproductid type "string" totalmaxdiscount type "number" type type "string" 	 description "must be time limited tiered absolute product discount" example in the example below we create a new discount which is not limited in time the discount itself works on the entire bill, and it gives a $1 discount for the first $1 spent, and $2 discount if the invoice is $10 { "targetproductid" "1", "promotiontimelimit" { "cycles" 0, "months" 0 }, "discountmap" { "1" 1, "10" 2 }, "totalmaxdiscount" null, "id" "c58986fc ee9f 427c 8163 3695c9dba0e1", "type" "time limited tiered absolute product discount", "promotionname" "my promo", "lockingstatus" "open" } example in the example below we create a new discount which is limited to 3 months the discount itself works on the entire bill, and it gives a $1 discount for the first $1 spent per invoice, and $2 discount if the total amount of all of the invoices that occurred since the discount was applied is $10 or more { "targetproductid" "1", "acrossbillingperiods" true, "promotiontimelimit" { "cycles" 0, "months" 0 }, "discountmap" { "1" 1, "10" 2 }, "totalmaxdiscount" null, "id" "c58986fc ee9f 427c 8163 3695c9dba0e1", "type" "time limited tiered absolute product discount", "promotionname" "my promo", "lockingstatus" "open" } time limited tiered absolute item discount granularity item condition time limited discount model tiered absolute schema \ type "object" properties acrossbillingperiods type "boolean" description "if true then the tier level discount will be detemined using the sum of all invoices since the promotion was applied " description type "string" dimensionconstraintmap type "object" description "a map of dimension key to value (string to string) indicating that this promotion can only be applied against usage that includes the given dimension values " additionalproperties type "string" discountmap type "object" 	 additionalproperties type "number" id type "string" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" measure type "object" promotionname type "string" promotiontimelimit type "object" properties cycles type "integer" months type "integer" targetproductitemid type "string" totalmaxdiscount type "number" type type "string" description "must be time limited tiered absolute item discount" example in the example below we create a new discount which is not limited in time the discount itself works on the usage bill of item "2d59a1d5 31d7 409d 9d78 843f31eb3e08", and it gives a $1 discount for the first $1 spent, and $2 discount if the invoice is $10 { "targetproductitemid" "2d59a1d5 31d7 409d 9d78 843f31eb3e08", "promotiontimelimit" { "cycles" 0, "months" 0 }, "discountmap" { "1" 1, "10" 2 }, "totalmaxdiscount" null, "id" "4f7c999d 213f 4472 87c1 1b26da690338", "type" "time limited tiered absolute item discount", "promotionname" "my promo", "lockingstatus" "open" } time limited tiered relative product discount granularity product condition time limited discount model tiered absolute schema \ type "object" properties acrossbillingperiods type "boolean" description "if true then the tier level discount will be detemined using the sum of all invoices since the promotion was applied " cyclemaxdiscount type "number" description type "string" discountcalculationstrategy type "string" description "step function, choose single tier" id type "string" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" pricetodiscountmap type "object" 	 additionalproperties type "number" promotionname type "string" promotiontimelimit type "object" properties cycles type "integer" months type "integer" targetproductid type "string" totalmaxdiscount type "number" type type "string" description "must be time limited tiered relative product discount" example in the example below we create a new discount which is limited to 18 billing cycles the discount itself works on the entire invoice, and it gives a 10% discount for the first $10 spent, and 20% discount for any larger amount there is a max of $19 per cycle and $100 for the entire life time of the discount the discount itself is calculated using the "step function" method mentioned above { "targetproductid" "1", "promotiontimelimit" { "cycles" 18, "months" 0 }, "pricetodiscountmap" { "0" 0 1, "10" 0 2 }, "discountcalculationstrategy" "step function", "totalmaxdiscount" 100, "cyclemaxdiscount" 19, "id" "67a63178 cdd4 48f6 a305 2038033abd9a", "type" "time limited tiered relative product discount", "promotionname" "my promo", "lockingstatus" "open" } time limited tiered relative item discount granularity item condition time limited discount model tiered absolute schema \ type "object" properties acrossbillingperiods type "boolean" description "if true then the tier level discount will be detemined using the sum of all invoices since the promotion was applied " cyclemaxdiscount type "number" description type "string" dimensionconstraintmap type "object" description "a map of dimension key to value (string to string) indicating that this promotion can only be applied against usage that includes the given dimension values " additionalproperties type "string" discountcalculationstrategy type "string" description "step function, choose single tier" id type "string" lastupdatetimeinmillis type "integer" lockingstatus type "string" description "open, close to deletions, close to changes, deprecated" pricetodiscountmap type "object" 	 additionalproperties type "number" promotionname type "string" promotiontimelimit type "object" properties cycles type "integer" months type "integer" targetproductitemid type "string" totalmaxdiscount type "number" type type "string" description "must be time limited tiered relative item discount" example in the example below we create a new discount which is limited to 18 billing cycles the discount itself works on the usage cost of item "806fdb8e 5bce 4b24 b6ce ab37ef857e89", and it gives a 10% discount for the first $10 spent, and 20% discount for any larger amount there is a max of $25 per cycle and $100 for the entire life time of the discount the discount itself is calculated using the "step function" method mentioned above { "targetproductitemid" "806fdb8e 5bce 4b24 b6ce ab37ef857e89", "promotiontimelimit" { "cycles" 18, "months" 0 }, "pricetodiscountmap" { "0" 0 1, "10" 0 2 }, "discountcalculationstrategy" "step function", "totalmaxdiscount" 100, "cyclemaxdiscount" 25, "id" "4ba106b9 2ef5 48b5 bc13 24dcf6cd635d", "type" "time limited tiered relative item discount", "promotionname" "my promo", "lockingstatus" "open" }