Promotions
Introduction
Promotions enable price reductions based on specific conditions. These conditions are defined as predicates in the promotion rules. A promotion can consist of multiple rules, but each rule can only belong to one promotion.
There are two types of promotions:
- catalogue promotions - reduce the product price visible to the customer,
- order promotions - applied on checkout / draft order when the object fulfilled the rule conditions.
All rules within promotion must be of one type CATALOGUE
or ORDER
.
The type of rule is determined by the promotion to which the rule is assigned.
The CATALOGUE
promotion consists only of CATALOGUE
rules with cataloguePredicate
defined,
and ORDER
promotion consists only of ORDER
rules with orderPredicate
defined.
Promotion rules specify the criteria that must be met, as well as the discount or reward that will be applied.
Catalogue promotions
The discounts from catalogue rules are automatically applied to all products that meet the conditions defined in the promotion.
For instance, if a product is priced at $9 and has a 10% discount, it will be available for $8.1.
The discount will be visible on ProductVariant.pricing
- priceUndiscounted
will be the price
before the promotion discount, and price
will have an applied discount.
The promotion discount will be also visible on the checkout line prices after adding the discounted
product to the card. The checkout subtotal is calculated as a sum of discounted prices of variants
added to the cart.
Saleor 3.17 (Deprecated)
When multiple promotions apply to one product, the promotion with the greatest savings is used. The discounts from rules within the single promotion are summed up.
Saleor 3.19+
When multiple promotions apply to one product, only the discount from the promotion rule that provides the maximum savings for the customer is applied. The discounts from rules within the single promotion are not summed up.
The catalogue discounts from promotions are calculated in the background. So the discounted price will not be instantly visible after promotion creation.
Examples of the use cases
- Define the product fixed or parentage discounts based on certain conditions.
- Define the discount available only for a specific period.
Order promotions
The discounts from order rules are automatically applied during checkout or draft orders when certain conditions are met. Only the discount from the promotion rule that provides the maximum savings for the customer is applied.
The order discounts can be combined with catalogue discounts, and in such cases, the discount is calculated based on the discounted price.
This kind of promotion discount requires providing the rewardType
that describes what
kind of discount will be applied after meeting the conditions.
Currently available reward types are:
SUBTOTAL_DISCOUNT
- applies the discount on the subtotal price,GIFT
- adds a gift to the order from available gifts.
For gift rewards, the promotion rule must specify the available gifts as product variants that can be added to checkout or draft orders. During calculations, the discounted prices of these variants (marked as possible gifts) are compared, and the variant with the highest discounted price is selected. This price is then compared to the savings offered by other promotion rules, such as those that apply discounts based on the subtotal price.
The gift is created as a new checkout or order line, with both its unit and total price set to 0. For now, only one gift can be assigned to the checkout/draft order.
For example, let's consider a checkout with only one product that is on catalogue discount, and the discounted price is $12. There are two promotion rules applied to this checkout.
- Promotion Rule A offers a 10% discount on the subtotal price. In this scenario, the discount will be 10% of $12, resulting in a savings of $1.2.
- Promotion Rule B adds a gift worth $5, which provides more savings compared to Promotion Rule A.
As a result, the gift worth $5 will be added to the checkout. The total price of the line is 0, so the total price of the checkout remains unchanged.
The number of PromotionRule
with ORDER
predicate type is limited to 100.
Promotions with the SUBTOTAL_DISCOUNT
do not work in conjunction with the TAX_APP
strategy.
Permissions
Managing promotions is available for users and apps with the MANAGE_DISCOUNTS
permission.
Glossary
- Promotion: Consists of promotion rules, and defines the start and end date when the discounts from the rules will be applied.
- Promotion type: Determine the type of promotion -
CATALOGUE
orORDER
. - Promotion rule: Defines the reward that will be given when the specified conditions are met.
- Catalogue predicate: Defines the conditions to be met on the catalogue level. When the conditions are met, the discount is applied automatically to corresponding variant prices.
- Order predicate: Defines the conditions to be met by checkout or draft order. When the conditions are met, the discount is applied automatically.
- Reward value: Defines the amount of the discount.
- Reward value type: Describe if the provided reward value is the fixed or percentage discount.
- Reward type: Describe what kind of reward is given when the promotion rule conditions are met. (Applicable only for order promotions).
- Base prices: Prices after applying catalogue promotions, do not include vouchers or order discounts.
- Gift: The checkout or order line that is added to checkout or draft order as a reward from order promotions.
Promotion type
The type of promotion determines whether to give the CATALOGUE
or ORDER
discount.
For the CATALOGUE
type, all rules within the promotion must have the cataloguePredicate
defined,
while for the ORDER
type, the orderPredicate
must be defined.
Rewards value
Reward value is defined on the promotion rule level and specifies the amount and type of the discount
that will be applied when the defined conditions are met.
Currently, there is only FIXED
or PERCENTAGE
discount available.
Reward type
Reward type is applicable only for order promotions and specify what kind of reward
will be given when the defined conditions are met.
Currently, only SUBTOTAL_DISCOUNT
is available so the order subtotal price will be reduced.
Base prices
Base prices are the prices after applying for catalogue promotions and do not include vouchers or order discounts. The subtotal price is the sum of the discounted total price of lines, the total price is subtotal plus the base delivery price.
Gift
A gift is a checkout or order line that is added as a reward from the order promotion rule. The price of this line is set to 0.
The possible gifts are defined on PromotionRule
with GIFT
reward type.
Predicates
Predicates define the conditions to be met to apply the reward.
Allows defining complex nested conditions in the same way as in where
filters, with AND
and OR
operators,
combined with operations (e.g. eq
, oneOf
).
To get to know how to build complex conditions reach out to the filters page.
Catalogue predicate
Catalogue level predicates allow defining conditions for variants, products, collections and categories.
Must be specified when CATALOGUE
predicate type is set.
Catalogue discount examples
Below, you can find examples of promotion rules with catalogue predicates that define a described catalogue discount.
- 10% discount on collection X
{
"promotionRule": {
"cataloguePredicate": {
"collectionPredicate": {
"ids": ["Q29sbGVjdGlvbjox"]
}
},
"rewardValueType": "PERCENTAGE",
"rewardValue": 10
}
}
- 10% discount on category X
{
"promotionRule": {
"cataloguePredicate": {
"categoryPredicate": {
"ids": ["Q29sbGVjdGlvbjox"]
}
},
"rewardValueType": "PERCENTAGE",
"rewardValue": 10
}
}
- 10% discount on variant X
{
"promotionRule": {
"cataloguePredicate": {
"variantPredicate": {
"ids": ["Q29sbGVjdGlvbjox"]
}
},
"rewardValueType": "PERCENTAGE",
"rewardValue": 10
}
}
- 10% discount on product X
{
"promotionRule": {
"cataloguePredicate": {
"productPredicate": {
"ids": ["Q29sbGVjdGlvbjox"]
}
},
"rewardValueType": "PERCENTAGE",
"rewardValue": 10
}
}
- $10 discount on collection X, or category X, or variant X or product X
{
"promotionRule": {
"cataloguePredicate": {
"OR": [
{
"collectionPredicate": {
"ids": ["Q2F0ZWdvcnk6OA=="]
}
},
{
"categoryPredicate": {
"ids": ["Q2F0ZWdvcnk6OA=="]
}
},
{
"variantPredicate": {
"ids": ["Q2F0ZWdvcnk6OA=="]
}
},
{
"productPredicate": {
"ids": ["Q2F0ZWdvcnk6OA=="]
}
}
]
},
"rewardValueType": "FIXED",
"rewardValue": 10
}
}
Order predicate
The order predicates enable the definition of conditions for checkout and draft order objects based on their attributes. Currently, it is only possible to define conditions based on the base total and base subtotal price.
Catalogue and order promotion discounts can be combined. Therefore, during checkout or draft order qualification, the discounted price (after applying any catalogue discount) is utilized.
Order discount examples
- 10% discount applied when the subtotal price is above $20, applied on subtotal price
{
"promotionRule": {
"orderPredicate": {
"discountedObjectPredicate": {
"baseSubtotalPrice": {
"range": { "gte": 20 }
}
}
},
"rewardValueType": "PERCENTAGE",
"rewardValue": 10,
"rewardType": "SUBTOTAL_DISCOUNT"
}
}
- $5 discount applied when the total price is above $50, applied on subtotal price
{
"promotionRule": {
"orderPredicate": {
"discountedObjectPredicate": {
"baseTotalPrice": {
"range": { "gte": 50 }
}
}
},
"rewardValueType": "FIXED",
"rewardValue": 5,
"rewardType": "SUBTOTAL_DISCOUNT"
}
}
- gift reward when the total price is above $50
{
"promotionRule": {
"orderPredicate": {
"discountedObjectPredicate": {
"baseTotalPrice": {
"range": { "gte": 50 }
}
}
},
"rewardValueType": null,
"rewardValue": null,
"rewardType": "GIFT",
"giftIds": ["UHJvZHVjdFZhcmlhbnQ6MzQ4", "UHJvZHVjdFZhcmlhbnQ6NDAw"]
}
}
Channel availability
Each rule can have assigned channels in which the discount will be applied. Promotion rules without any channels will not apply anywhere.
The promotion rule can have multiple channels assigned, but there is a restriction to that.
When the rule reward value type is FIXED
, all assigned channels must have the same currency.
Creating the promotion
To create a promotion use promotionCreate
mutation.
The mutation takes the following input:
name
: name of the promotion;type
: type of the promotion;description
: optional description of the promotion;startDate
: defines when the promotion becomes active;endDate
: defines when the promotion becomes ends;rules
: optional list of promotion rules. The rules could be also created bypromotionRuleCreate
mutation.
Defining the promotion
Below is an example of promotion creation without any rules.
mutation promotionCreate($input: PromotionCreateInput!) {
promotionCreate(input: $input) {
promotion {
id
name
type
description
startDate
endDate
}
}
}
Query variables:
{
"input": {
"name": "Example sale",
"type": "CATALOGUE",
"description": {
"blocks": [
{
"type": "paragraph",
"data": {
"text": "Test example sale."
}
}
]
},
"startDate": "2023-06-06T00:00:00.00+00:00"
}
}
As a response, we will get a newly created promotion:
{
"data": {
"promotionCreate": {
"promotion": {
"id": "UHJvbW90aW9uOjEyMzA0YmM4LTA2ZTMtNDg1Mi05ODU1LWM4ZDkyMDgzNTYwZA==",
"name": "Example sale",
"type": "CATALOGUE",
"description": {
"blocks": [
{
"type": "paragraph",
"data": {
"text": "Test example sale."
}
}
]
},
"startDate": "2023-06-06T00:00:00+00:00",
"endDate": null
}
}
}
}
Adding promotion rule
To add a promotion rule to the promotion use promotionRuleCreate
mutation.
The mutation takes the following input:
name
: optional name of the promotion rule.description
: optional description of the promotion rule.promotion
: define to which promotion the rule should be part of.channels
: define in which channels the rule should be applicable.rewardValueType
: define the type of discountPERCENTAGE
/FIXED
.rewardValue
: define the value of the discount.rewardType
: define the type of reward. Required for order promotion rules.gifts
: define product variants that might be added as a gift. Required forGIFT
reward type.cataloguePredicate
: defines the conditions to be met to apply catalogue discount. Required for the rule that belongs toCATALOGUE
promotion. Allows defining complex nested conditions withAND
andOR
operators.orderPredicate
: defines the conditions to be met to apply order discount. Required for the rule that belongs toORDER
promotion. Allows defining complex nested conditions withAND
andOR
operators.
Creation of catalogue promotion rule
The following example demonstrates the creation of a catalogue promotion rule that applies a 50% discount on all products from a collection and categories with specified IDs. The rule will be applicable on two channels.
mutation promotionRuleCreate($input: PromotionRuleCreateInput!) {
promotionRuleCreate(input: $input) {
promotionRule {
id
name
description
promotion {
id
}
channels {
id
}
rewardValueType
rewardValue
cataloguePredicate
}
}
}
To define such a discount the catalogue predicate with OR
operator is used, to
mark that any products from given collections or categories are included in this promotion.
For this kind of promotion rule, you must provide cataloguePredicate
,
the rule must be part of CATALOGUE
promotion.
Query variables:
{
"input": {
"name": "50% catalogue discount",
"promotion": "UHJvbW90aW9uOjEyMzA0YmM4LTA2ZTMtNDg1Mi05ODU1LWM4ZDkyMDgzNTYwZA==",
"channels": ["Q2hhbm5lbDoy", "Q2hhbm5lbDo0"],
"rewardValueType": "PERCENTAGE",
"rewardValue": "50",
"cataloguePredicate": {
"OR": [
{
"categoryPredicate": {
"ids": ["Q2F0ZWdvcnk6MQ==", "Q2F0ZWdvcnk6NDQ="]
}
},
{
"collectionPredicate": {
"ids": ["Q29sbGVjdGlvbjo1"]
}
}
]
}
}
}
As a result, we get a newly created promotion rule:
{
"data": {
"promotionRuleCreate": {
"promotionRule": {
"id": "UHJvbW90aW9uUnVsZTo0NThmMTFlZC04NTIxLTQ0YTgtYmM2YS1iNjNmNzg0Yzc0ZmM=",
"name": "50% catalogue discount",
"description": null,
"promotion": {
"id": "UHJvbW90aW9uOjEyMzA0YmM4LTA2ZTMtNDg1Mi05ODU1LWM4ZDkyMDgzNTYwZA=="
},
"channels": [
{
"id": "Q2hhbm5lbDoy"
},
{
"id": "Q2hhbm5lbDo0"
}
],
"rewardValueType": "PERCENTAGE",
"rewardValue": 50,
"predicateType": "CATALOGUE",
"cataloguePredicate": {
"OR": [
{
"categoryPredicate": {
"ids": ["Q2F0ZWdvcnk6MQ==", "Q2F0ZWdvcnk6NDQ="]
}
},
{
"collectionPredicate": {
"ids": ["Q29sbGVjdGlvbjo1"]
}
}
]
}
}
}
}
}
Creation of order promotion rule with subtotal discount
The following example demonstrates the creation of an order promotion rule that
gives 10% subtotal price discount on checkout/draft order that subtotal price is greater
than or equal to 20.
For this kind of promotion rule, you must provide orderPredicate
and rewardType
,
it can be defined only for promotion with ORDER
type.
Price-based predicates are only allowed for promotion rules in which all assigned channels have the same currency.
mutation promotionRuleCreate($input: PromotionRuleCreateInput!) {
promotionRuleCreate(input: $input) {
promotionRule {
id
name
description
promotion {
id
}
channels {
id
}
rewardValueType
rewardValue
orderPredicate
}
}
}
Query variables:
{
"input": {
"name": "10% percentage order discount",
"promotion": "UHJvbW90aW9uOjEyMzA0YmM4LTA2ZTMtNDg1Mi05ODU1LWM4ZDkyMDgzNTYwZA==",
"channels": ["Q2hhbm5lbDoy"],
"rewardValueType": "PERCENTAGE",
"rewardValue": "10",
"rewardType": "SUBTOTAL_DISCOUNT",
"orderPredicate": {
"discountedObjectPredicate": {
"baseSubtotalPrice": {
"range": { "gte": 20 }
}
}
}
}
}
Creation of order promotion rule with gift reward
The following example demonstrates the creation of a gift order promotion rule that
gives add a gift to checkout/draft order that subtotal price is greater
than or equal to 20.
For this kind of promotion rule, you must provide orderPredicate
, rewardType
, and gifts
,
it can be defined only for promotion with ORDER
type.
For this kind of promotion rule, the rewardValue
and rewardValueType
are empty.
Price-based predicates are only allowed for promotion rules in which all assigned channels have the same currency.
The limit of assigned gifts to the promotion rule is 500.
mutation promotionRuleCreate($input: PromotionRuleCreateInput!) {
promotionRuleCreate(input: $input) {
promotionRule {
id
name
description
promotion {
id
}
channels {
id
}
rewardValueType
rewardValue
orderPredicate
giftIds
}
}
}
Query variables:
{
"input": {
"name": "Gift order rule",
"promotion": "UHJvbW90aW9uOjEyMzA0YmM4LTA2ZTMtNDg1Mi05ODU1LWM4ZDkyMDgzNTYwZA==",
"channels": ["Q2hhbm5lbDoy"],
"rewardType": "GIFT",
"orderPredicate": {
"discountedObjectPredicate": {
"baseSubtotalPrice": {
"range": { "gte": 20 }
}
}
},
"gifts": ["UHJvZHVjdFZhcmlhbnQ6MzQ4", "UHJvZHVjdFZhcmlhbnQ6NDAw"]
}
}
Discounted price recalculations
Discounted prices are calculated based on catalogue promotions.
The discounts for specified catalogues are calculated asynchronously, so the discounted price will be not visible immediately after promotion creation or activation.
The discounted price is visible on ProductVariant.pricing
.
Below you can see the pricing of the variant included in the newly created promotion:
{
"data": {
"productVariant": {
"id": "UHJvZHVjdFZhcmlhbnQ6MzM1",
"pricing": {
"onSale": true,
"priceUndiscounted": {
"gross": {
"amount": 90.0
}
},
"price": {
"gross": {
"amount": 45.0
}
},
"discount": {
"gross": {
"amount": 45.0
}
}
}
}
}
}
As you can see, the variant is onSale
and the price was reduced by half.
Promotion events history
We store the promotion history in events. Each action related to the creation, update, or deletion of promotions and promotion rules, and activation and deactivation of promotion is recorded in an event. The list of possible events is represented by PromotionEventsEnum.
You can check promotion events by fetching promotion.events
. As it's shown
in the example below:
query Promotion($id: ID!) {
promotion(id: $id) {
id
events {
... on PromotionEventInterface {
type
date
createdBy {
... on User {
id
}
}
}
... on PromotionRuleEventInterface {
ruleId
}
}
}
}
Query variable:
{
"id": "UHJvbW90aW9uOmYxMWQ5ZWRiLTI5ZjktNDA5Yy05MjdlLTNjOGMzMDFjZjM2NA=="
}
Response:
{
"data": {
"promotion": {
"id": "UHJvbW90aW9uOjEyMzA0YmM4LTA2ZTMtNDg1Mi05ODU1LWM4ZDkyMDgzNTYwZA==",
"events": [
{
"type": "PROMOTION_CREATED",
"date": "2023-09-21T12:28:16.457902+00:00",
"createdBy": {
"id": "VXNlcjox"
}
},
{
"type": "PROMOTION_STARTED",
"date": "2023-09-21T12:28:16.464749+00:00",
"createdBy": {
"id": "VXNlcjox"
}
},
{
"type": "RULE_CREATED",
"date": "2023-09-21T12:30:17.520316+00:00",
"createdBy": {
"id": "VXNlcjox"
},
"ruleId": "UHJvbW90aW9uUnVsZTo1MjIwYmViZS02MjczLTRkNjUtYTNkZC1iYjNlYmI4MjllYjA="
}
]
}
}
}
Webhooks
All promotion actions also generate asynchronous webhooks that can be used for reacting
to the events emitted by Saleor, e.g. PROMOTION_CREATED
, PROMOTION_STARTED
, PROMOTION_ENDED
.
The WebhookEventTypeAsyncEnum
represents the full list of asynchronous webhooks.
You can learn more about webhooks here.
Completing checkout with a promotion discount
In the case of a variant on promotion, the applied discount is visible only on the order and lines
prices; the order.discounts
field is empty. Let's see the following example,
for completing the checkout with two items of the product included in the promotion
that reduces the price of the single item by $5.
{
"data": {
"checkoutComplete": {
"order": {
"id": "T3JkZXI6YzQ0YTAzNDgtZDlhYy00ZDkyLWFiZWUtMmNjNzg2OWJkOWQy",
"status": "UNFULFILLED",
"totalCaptured": {
"amount": 30.0
},
"subtotal": {
"gross": {
"amount": 30.0
}
},
"total": {
"gross": {
"amount": 30.0
}
},
"undiscountedTotal": {
"gross": {
"amount": 40.0
}
},
"discounts": [],
"lines": [
{
"quantity": 2,
"totalPrice": {
"gross": {
"amount": 30.0
}
},
"unitPrice": {
"gross": {
"amount": 15.0
}
},
"undiscountedUnitPrice": {
"gross": {
"amount": 20.0
}
},
"unitDiscount": {
"amount": 5.0
}
}
]
},
"errors": []
}
}
}
The promotion discount is not visible on checkout.discount.amount
.
As you can see, the order.discounts
field is empty, but there is a difference between
order.total
and order.undiscountedTotal
. The applied discount can be checked
on the unit level in the order.lines.unitDiscount
field, as well as by comparing
the order.lines.undiscountedUnitPrice
and order.lines.unitPrice
. The sum of line unit
discounts multiplied by the quantity of the line gives the total discount, which is
equal to the difference between order.total
and order.undiscountedTotal
.
Processing checkout with an applied order promotion
Below you can see an example of checkout data with an applied order discount from an order promotion that applied $5 discount on objects with subtotal above $20.
{
"data": {
"checkout": {
"id": "Q2hlY2tvdXQ6YzJlNTlmNTUtZjYzOS00MTc2LWI0ZjMtMGFjYWE1Y2FiZDlm",
"email": "customer@example.com",
"token": "c2e59f55-f639-4176-b4f3-0acaa5cabd9f",
"channel": {
"slug": "default-channel"
},
"voucherCode": null,
"discount": {
"amount": 5.0
},
"discountName": "Example order promo: order rule",
"totalPrice": {
"gross": {
"amount": 42.5,
"currency": "USD"
}
},
"subtotalPrice": {
"gross": {
"amount": 35.0,
"currency": "USD"
}
},
"shippingPrice": {
"gross": {
"amount": 7.5,
"currency": "USD"
}
},
"deliveryMethod": {
"id": "U2hpcHBpbmdNZXRob2Q6MQ=="
},
"lines": [
{
"id": "Q2hlY2tvdXRMaW5lOjkzOTk0OTgxLThmNWItNDg1OS04NzZmLTM1MmY5YjEyMTJlMg==",
"quantity": 2,
"undiscountedTotalPrice": {
"amount": 40.0
},
"totalPrice": {
"gross": {
"amount": 35.0
}
},
"unitPrice": {
"gross": {
"amount": 17.5
}
},
"undiscountedUnitPrice": {
"amount": 20.0
},
"variant": {
"pricing": {
"onSale": false,
"discount": null,
"priceUndiscounted": {
"gross": {
"amount": 20.0
}
},
"price": {
"gross": {
"amount": 20.0
}
}
}
}
}
]
}
}
}
The discount is visible on the discount.amount
field at the checkout level,
as well as on the line prices, which are discounted.
After completing the checkout we get an order with discounted prices:
{
"data": {
"checkoutComplete": {
"order": {
"id": "T3JkZXI6ZWVjNTFjZWItZTlkZi00ZmYzLTgxYWUtYzQ4ODYyNjQwNWQ1",
"status": "UNFULFILLED",
"totalCaptured": {
"amount": 42.5
},
"subtotal": {
"gross": {
"amount": 35.0
}
},
"total": {
"gross": {
"amount": 42.5
}
},
"undiscountedTotal": {
"gross": {
"amount": 47.5
}
},
"discounts": [
{
"name": "Example order promo: order rule",
"type": "ORDER_PROMOTION",
"valueType": "FIXED",
"amount": {
"amount": 5.0
}
}
],
"lines": [
{
"quantity": 2,
"totalPrice": {
"gross": {
"amount": 35.0
}
},
"unitPrice": {
"gross": {
"amount": 17.5
}
},
"undiscountedUnitPrice": {
"gross": {
"amount": 20.0
}
},
"unitDiscount": {
"amount": 2.5
}
}
]
},
"errors": []
}
}
}
Catalogue and order promotions
Catalogue and order promotions can be mixed. In such cases the order discount is applied on the discounted price. Let's see the example:
{
"data": {
"checkout": {
"id": "Q2hlY2tvdXQ6NjA1YWU2NWYtNjYwZC00OGY1LWI5MzMtMjVjYjEzM2U1MWU3",
"email": "admin@example.com",
"token": "605ae65f-660d-48f5-b933-25cb133e51e7",
"channel": {
"slug": "default-channel"
},
"voucherCode": null,
"discount": {
"amount": 5.0
},
"discountName": "Example order promo: order rule",
"totalPrice": {
"gross": {
"amount": 30.5,
"currency": "USD"
}
},
"subtotalPrice": {
"gross": {
"amount": 23.0,
"currency": "USD"
}
},
"shippingPrice": {
"gross": {
"amount": 7.5,
"currency": "USD"
}
},
"deliveryMethod": {
"id": "U2hpcHBpbmdNZXRob2Q6MQ=="
},
"lines": [
{
"id": "Q2hlY2tvdXRMaW5lOjgwYTk5YmE5LWY4YTUtNDhhZS1hN2FlLWMyMDRmY2MxNDEzNw==",
"quantity": 2,
"undiscountedTotalPrice": {
"amount": 40.0
},
"totalPrice": {
"gross": {
"amount": 23.0
}
},
"unitPrice": {
"gross": {
"amount": 11.5
}
},
"undiscountedUnitPrice": {
"amount": 20.0
},
"variant": {
"pricing": {
"onSale": true,
"discount": {
"gross": {
"amount": 6.0
}
},
"priceUndiscounted": {
"gross": {
"amount": 20.0
}
},
"price": {
"gross": {
"amount": 14.0
}
}
}
}
}
]
}
}
}
The $5 discount shown on checkout.discount.amount
is a result of the order promotion.
The line displaying discounted prices includes both the catalogue discount and the order discount.
To verify the catalogue discount, refer to checkout.lines.variant.prices
.
In this example, the catalogue discount is $6 for each quantity of 1,
resulting in a total discount of $6 * 2 quantities. Additionally, there is a $5 discount
from the order discount, making a total discount of $17.
This amount matches the difference between the undiscountedTotalPrice
and totalPrice
.
An order with discounted prices after completing the checkout:
{
"data": {
"checkoutComplete": {
"order": {
"id": "T3JkZXI6OTM3ZDkxMjUtMjA0Ny00ZjE2LWE1MzItZTAwMTUyOWMyYmEz",
"status": "UNFULFILLED",
"totalCaptured": {
"amount": 30.5
},
"subtotal": {
"gross": {
"amount": 23.0
}
},
"total": {
"gross": {
"amount": 30.5
}
},
"undiscountedTotal": {
"gross": {
"amount": 47.5
}
},
"discounts": [
{
"name": "Example order promo: order rule",
"type": "ORDER_PROMOTION",
"valueType": "FIXED",
"amount": {
"amount": 5.0
}
}
],
"lines": [
{
"quantity": 2,
"totalPrice": {
"gross": {
"amount": 23.0
}
},
"unitPrice": {
"gross": {
"amount": 11.5
}
},
"undiscountedUnitPrice": {
"gross": {
"amount": 20.0
}
},
"unitDiscount": {
"amount": 8.5
}
}
]
},
"errors": []
}
}
}
Completing checkout with a gift reward
Below you can see an example of checkout data with an applied gift reward from an order promotion that applies on objects with subtotal above $20.
{
"data": {
"checkout": {
"id": "Q2hlY2tvdXQ6NTdkZjViYjUtNWY3My00NTZjLTg4YjgtOTgwZGQ3OWZiZmE5",
"email": "admin@example.com",
"token": "57df5bb5-5f73-456c-88b8-980dd79fbfa9",
"channel": {
"slug": "default-channel"
},
"voucherCode": null,
"discount": {
"amount": 0.0
},
"discountName": null,
"totalPrice": {
"gross": {
"amount": 40.0
}
},
"subtotalPrice": {
"gross": {
"amount": 40.0
}
},
"shippingPrice": {
"gross": {
"amount": 0.0
}
},
"deliveryMethod": null,
"lines": [
{
"id": "Q2hlY2tvdXRMaW5lOmU5ZmI3YjY3LTA4ZjctNDQzZi1iMWNjLWE1ZmJlNGU0NjcxMg==",
"quantity": 2,
"undiscountedTotalPrice": {
"amount": 40.0
},
"totalPrice": {
"gross": {
"amount": 40.0
},
"net": {
"amount": 40.0
}
},
"unitPrice": {
"gross": {
"amount": 20.0
},
"net": {
"amount": 20.0
}
},
"undiscountedUnitPrice": {
"amount": 20.0
}
},
{
"id": "Q2hlY2tvdXRMaW5lOmMwNzhjNGQyLWI1MzUtNDhkMy04MDlmLTA1ZDUyYjY3MWFiNQ==",
"quantity": 1,
"undiscountedTotalPrice": {
"amount": 50.0
},
"totalPrice": {
"gross": {
"amount": 0.0
},
"net": {
"amount": 0.0
}
},
"unitPrice": {
"gross": {
"amount": 0.0
},
"net": {
"amount": 0.0
}
},
"undiscountedUnitPrice": {
"amount": 50.0
}
}
]
}
}
}
We can see an extra line added to checkout which is marked with isGift
flag.
The unit and total price of this line is set to 0.
The checkout discount.amount
is 0.
After completing the checkout we get an order with the gift line:
{
"data": {
"checkoutComplete": {
"order": {
"id": "T3JkZXI6YTAxYjEzMWQtZjA0Ny00ZWM3LTk3OWUtZWUyMGEzYzBjNDk2",
"status": "UNFULFILLED",
"totalCaptured": {
"amount": 47.5
},
"subtotal": {
"gross": {
"amount": 40.0
}
},
"total": {
"currency": "USD",
"gross": {
"amount": 47.5
}
},
"undiscountedTotal": {
"currency": "USD",
"gross": {
"amount": 547.5
}
},
"discounts": [],
"lines": [
{
"quantity": 2,
"totalPrice": {
"gross": {
"amount": 40.0
}
},
"unitPrice": {
"gross": {
"amount": 20.0
}
},
"undiscountedUnitPrice": {
"gross": {
"amount": 20.0
}
},
"unitDiscount": {
"amount": 0.0
}
},
{
"quantity": 1,
"totalPrice": {
"gross": {
"amount": 0.0
}
},
"unitPrice": {
"gross": {
"amount": 0.0
}
},
"undiscountedUnitPrice": {
"gross": {
"amount": 500.0
}
},
"unitDiscount": {
"amount": 500.0
}
}
]
},
"errors": []
}
}
}
Catalogue Promotion and Voucher
Catalogue promotions and vouchers can be combined. In this case, the voucher discount is applied to the price after the promotion discount. Here you can find the example of such scenario.
Order Promotion and Voucher
Order promotion cannot be mixed with Vouchers. When a voucher code is added, the discount from the order promotion is not applied.