Promotions
Fundamentals of a promotion
- Promotions can be assigned to specific shops and are then only valid in these shops. Promotions can also be valid in several shops at the same time.
- Within one shop, a promotion can be configured to be valid in specific countries. Promotions can also be valid in multiple countries at the same time.
- Audiences are finely tuned customer segments that enable precise customer outreach. You can define for which audiences a promotion is valid. This is optional, a promotion can also be valid for all audiences.
- Each promotion has a set of basic configurations.
Promotion configuration
Name | Description |
---|---|
Name | Each promotion has a specific name, that you can freely choose. The name is not unique, so multiple promotions can have the same name. |
Display name | Each promotion can have a Display name. This is the name that will be displayed in the Shop, and therefore visible to the end user. If you do not set a name, the system will automatically set it to Null, and the shop will resolve this into a string, with the default translation of voucher . You can update this translation via your crowdin project under the string: fallbackCodeName |
Combinable | Configuration which states whether the promotion can be combined with others and if so, with which ones. You can either include or exclude other promotions. |
Schedule | Period in which the promotion is valid. |
State | A promotion can be either active or inactive. Promotions in the state inactivate are not returned by the Storefront API, and are also not valid when applying them to items in a basket/order. |
Priority | Priority refers to the ranking of a promotion when compared to other promotions. Useful in the storefront, when running multiple promotions and you want to evaluate, which one has a higher priority by comparing. |
Custom Data | Custom data represents a JSON object, that you can use freely to persist any data that you like. |
Supported Effect | Automatic Discount or Buy X Get Y. |
Promotion Conditions | Conditions are special rules that must be satisfied in order for the promotion to be applied. Read more about them below. |
Promotion conditions
To each promotion, conditions can be assigned. Conditions are special rules that must be satisfied in order for the promotion to be applied. A distinction is made between two types of conditions:
Global conditions
Global conditions are checked against general customer- or basket/order data. The promotion is only considered valid if the global condition is met. If the global condition isn't met, the entire promotion is invalid, regardless of whether the item conditions are met. Typical examples for global conditions are:
- Minimum order value is greater or equal than €100
- Customer is in group “VIP”
- Basket/order contains more than 3 items of a specific brand
Item Conditions
Item conditions are checked against the item you are trying to apply the promotion to. This is useful, when you want to limit the set of items, which can benefit from a promotion, for instance
- 15% off of jeans
- 10% off of all items with attribute group “deal”
- Conditions can be connected by “and” or “or” operators as well.
By mix and matching global and item conditions, you can create specific promotions that serve your individual promotion cases.
The conditions are defined using the Google Common Expression Language.
The implementation is based on Go, you can find the language definition here. Cel-go has multiple extensions, currently we support the Math extension, which supports two additional functions: math.greatest()
and math.least()
Note that the attributes on payload.customer.*
are only validated in the Checkout, not the Storefront.
If you want to evaluate certain customer conditions, we suggest using the audiences-feature, as audiences are already validated in the Storefront.
Condition examples
payload.items.filter(it, it.price == math.greatest(payload.items.map(i, i.price)))[0].price == item.price
payload.items.filter(it, it.price == math.least(payload.items.map(i, i.price)))[0].price == item.price
Admin API
The Admin API offers several endpoints for managing promotions.
Create promotion
SCAYLE allows you to create promotions.
Method Signature
let response = await client.apis.Promotions.createPromotion({}, {requestBody: promotion});
let createdPromotion = response.body;
Options
The createPromotion
method can be used with an optional query parameter:
Parameter | Details |
---|---|
with | String
|
Request Body
Properties marked with a *
are required.
Property | Description |
---|---|
name* | String Defines the name of the promotion. |
status* | String Defines the status of the promotion.
|
schedule* | Object Defines the time range when a promotion is active. |
companyIds* | Integer[] A list of company ids where the promotion takes place. |
shopCountryIds* | Object Defines the shop countries in which the promotion will be available. |
effect* | Object The effect that will be applied if all conditions are satisfied. See Effects |
activationType* | String
|
level* | String
|
conditions* | Object[] Defines a list of conditions that must be satisfied for applying a promotion to the customers basket. See Conditions |
displayName | Object Example
|
priority | Integer Defines the priority of the promotion. |
siblingPromotions | See Sibling Promotions |
audiences | Object See Audiences |
customData | Object
|
tiers | Object[] Defines a list of tiers that allow configuring different effect values depending on the minimum order value. See Tiers |
usageLimit | Object Usage limit configuration See Usage Limit |
Schedule
Property | Description |
---|---|
from* | String Defines the start date of the promotion. |
to* | String Defines the end date of the promotion. Example: 2024-05-01T12:00:00+00:00 |
ShopCountryIds
The properties allowList
and blockList
are mutually exclusive, meaning, you cannot pass both at the same time. At the same time, one of both is required.
Property | Description |
---|---|
allowList | Integer[] A list of shop country ids where the promotion is active. |
blockList | Integer[] A list of shop county ids where the promotion is not active. This means, the promotion will be active in all other shop countries. |
Effects
Property | Description |
---|---|
type* | String Defines the type of the promotion. Valid values are: |
additionalData* | Object Supplementary data required to complete the effect definition. See Buy X Get Y or Automatic Discount |
Effect - Additional Data - Buy X Get Y
When the promotion conditions are satisfied, the customer will receive n items for free. (The list of which items will be given for free and how many can be defined during promotion creation).
Property | Description |
---|---|
variantIds* | Integer[]
The customer will be able to pick n items from the list. |
maxCount* | Integer “For each blue shirt you buy, get 2 free socks”
|
maxCountType | String Valid values are:
|
eligibleItemsQuantity | Integer Has to be configured together with maxCountType .Used for calculating of limit free items. |
Effect - Additional Data - Automatic Discount
When the promotion conditions are satisfied, the customer will receive a discount on specific items or the whole basket.
Property | Description |
---|---|
type* | String Valid values are:
|
value* | Float
absolute
* The currency is inherited from the shop country the promotion is being applied to. |
Conditions
Conditions are special rules that must be satisfied in order for the promotion to be applied. These rules must follow the Google Common Expression Language syntax.
Conditions can be applied on two different levels, global and item. Global conditions are applied only once per payload / basket, while item conditions are checked for each item in the basket. Anything other than item related conditions should be put into conditions on level global.
- When only item level conditions are satisfied, effects are applied for each item.
- When only global level conditions are satisfied, effects are applied on basket level.
- When both, global and item level conditions, are satisfied, they are applied accordingly.
Property | Description |
---|---|
level* | String Valid values are:
|
key* | String Key of the condition. Can be used to identify which condition failed in the validate endpoint. Example mov_100 |
condition* | String A Google Common Expression Language valid condition. Example payload.items.exists(i, 11003 in i.variant.id) |
Sibling Promotions
Sibling promotions allow to create a new promotion combined with other promotions defined in siblingPromotions.
The properties allowList
and blockList
are mutually exclusive, meaning, you cannot pass both at the same time. At the same time, one of both is required.
Property | Description |
---|---|
level* | String Valid values are:
|
enabled* | Boolean
|
allowList | String The list of promotion ids that can be applied together with the promotion ( enabled has to be true ). |
blockList | String The list of promotion ids that cannot be applied together with the promotion ( enabled has to be true ). |
Audiences
Allows promotion engine users to tailor promotions to particular group of customers. An audience is a collection of customers grouped to be used effectively in/for a promotion.
Example
Black Friday Influencers , VIP_Members , High Value Customers, Trend Lovers
The properties allowList
and blockList
are mutually exclusive, meaning, you cannot pass both at the same time. At the same time, one of both is required.
Property | Description |
---|---|
allowList | String[] The list of audience ids that can use this promotion. When included in the list, the promotion is only visible to customers that belong to an audience listed in the |
blockList | String[] A list of audience ids that cannot use this promotion. When providing blockList , it is visible to all customers except the ones that are part of an audience that it listed in the blockList . |
Tiers
Promotion tiers allow configuring different effect values depending on the MOV (Minimum Order Value). effect.additional_data
can have different values for each individual tier.
Basically, current tier effect values are merged with promotion.effect
. That means, it is not necessary to include all effect.additional_data
values in the tier.effect
, it is enough to add only values that are changed.
Example
- when MOV reaches 100 EUR, customer gets 10% discount
- when MOV reaches 150 EUR, customer gets 15% discount
Property | Description |
---|---|
name* | String Defines the name of the tier. |
effect* | Object The effect that will be applied if all conditions are satisfied. See Tier Effect |
mov* | Integer Minimal order value requirement for a tier. Value should be in a fractional currency (e.g. cents), if a currency has fractions. Example 10000 |
Tier Effect
Property | Description |
---|---|
additionalData* | Object Supplementary data required to complete the effect definition. See Buy X Get Y or Automatic Discount |
Usage Limit
Property | Description |
---|---|
promotion* | Object |
promotionCodes* | Object See Usage Limit - Promotion Codes |
Usage Limit Promotion
Property | Description |
---|---|
count* | Integer
|
Usage Limit Promotion Codes
Property | Description |
---|---|
count* | Integer
|
type* | String Valid values are:
|
Example
let response = await adminApi.apis.Promotions.createPromotion({
with: "customData"
}, {
requestBody: {
"name": "Christmas Promotion",
"status": "active",
"shopCountryIds": {
"allowList": [139, 554]
},
"companyIds": [100],
"schedule": {
"from": "2023-05-10T10:00:00+01:00",
"to": "2024-05-10T10:00:00+01:00"
},
"effect": {
"type": "buy_x_get_y",
"additionalData": {
"variantIds": [12389244, 23985437],
"maxCount": 2,
"maxCountType": "per_eligible_items_quantity",
"eligibleItemsQuantity": 1
}
},
"activationType": "automatic",
"level": "basket",
"priority": 10,
"displayName": {
"de_DE": "Weihnachtsaktion",
"en_US": "Christmas Promotion"
},
"customData": {
"anything": "you want to provide"
},
"audiences": {
"allowList": ["645e0c241a93369ff53f26e0"]
},
"siblingPromotions": {
"enabled": true,
"blockList": ["646235bf496f8f56171c3762"],
"level": "basket"
},
"usageLimit": {
"promotion": {
"count": 10
},
"promotionCodes": {
"count": 10,
"type": "order"
}
},
"conditions": [
{
"level": "global",
"key": "mov_100",
"condition": "payload.items.exists(i. 11003 in i.variant.id)"
},
{
"level": "item",
"key": "mov_100",
"condition": "item.color == 'yellow'"
}
]
}
});
let createdPromotion = response.body;
console.log(createdPromotion.id);
Update promotion
Updating an existing promotion follows the same schema as for creating new promotions. Therefore, you can simply refer to the request body and schema above.
Method signature
let response = await client.apis.Promotions.updatePromotion(
{promotionId: "promotionId"},
{requestBody: promotion}
);
let updatedPromotion = response.body;
Request Body
Please refer to the create promotion request body.
Example
let promotion = {
"name": "Christmas Promotion",
"status": "active",
"shopCountryIds": {
"blockList": [ 139, 554 ]
},
"activationType": "code",
"level": "basket",
"companyIds": [ 100 ],
"schedule": {
"from": "2023-05-10T10:00:00+01:00",
"to": "2024-05-10T10:00:00+01:00"
},
"effect": {
"type": "buy_x_get_y",
"additionalData": {
"variantIds": [12389244, 23985437],
"maxCount": 2,
"maxCountType": "per_eligible_items_quantity",
"eligibleItemsQuantity": 1
}
}
}
let response = await client.apis.Promotions.updatePromotion(
{promotionId: "645e0c241a93369ff53f26e0", with: "customData"},
{requestBody: promotion}
);
let updatedPromotion = response.body;
console.log(updatedPromotion.id);
List promotions
You can also request several promotions. We suggest to fine-tune your search, e.g. by combining filters and using pagination. As search results are paginated, you can set the amount of promotions displayed per page.
Method signature
let response = await adminApi.apis.Promotions.getPromotions(options);
let promotions = response.body.entities;
Options
The getPromotions endpoint can be used with the following optional query parameters:
Parameter | Details |
---|---|
filters[id] | String
|
filters[name] | String
|
filters[companyId] | String
|
filters[activeAt] | String
|
filters[shopCountryId] | String
|
filters[status] | String Valid values are:
|
filters[effect] | String Valid values are:
|
filters[audienceId] | String
|
filters[activationType] | String Valid values are:
|
filters[promotionCodes] | String
|
with | String The parameter allows you to include the following nested resources in the response:
Example
|
limit | Integer Maximum number of entities in the result. When fetching entities with children, the limit always applies to the amount of parent entities (max. 1000). |
cursor | String Example
|
Example
let response = await adminApi.apis.Promotions.getPromotions({
"filters[id]": ["645e0c241a93369ff53f26e0", "f0c07b9967fa64f3ab0bdec0"],
"filters[name]": "Christmas Promotion",
"filters[activeAt]": "2024-04-09T10:00:00+01:00",
"filters[shopCountryId]": [1, 2, 3],
"filters[companyId]": [100, 200],
"filters[status]": ["active", "inactive", "archived"],
"filters[effect]": "automatic_discount",
"filters[audienceId]": ["48f75314ba216a213d32868e", "02bc1c8cb9b7bcd39247ebd0"],
"filters[activationType]": "code",
"filters[promotionCodes]": ["d27d75a754bf13d014296633", "9a22a66d2f1101cdb5b54502"],
"cursor": "Mgo=",
"limit": 100,
"with": "customData"
});
let promotions = response.body.entities;
promotions.forEach(
promotion => console.log(promotion.id)
);
Get promotion
SCAYLE allows you to retrieve a promotion by its ID.
Method signature
let response = await adminApi.apis.Promotions.getPromotion(options);
let promotions = response.body;
Options
The createPromotion endpoint can be used with an optional query parameter:
Parameter | Details |
---|---|
with | String
Example
|
Example
let response = await adminApi.apis.Promotions.getPromotion({
promotionId: "645e0c241a93369ff53f26e0",
with: "customData"
});
let promotions = response.body;
console.log(promotion.id);
Delete promotion
SCAYLE allows you to delete a promotion by its ID. The request returns a 204 No Content
on success.
Method signature
adminApi.apis.Promotions.deletePromotion({
promotionId: "promotionId"
});
Example
adminApi.apis.Promotions.deletePromotion({
promotionId: "645e0c241a93369ff53f26e0"
});
Deprecated (will be removed in near future)
Use Admin API:
Required parameters
Parameter | Type | Example | Definition |
---|---|---|---|
name | string | Christmas Promotion | Defines the name of the promotion |
schedule.from | string | 2023-05-10T10:00:00+01:00 | Defines the start date of the promotion |
schedule.to | string | 2024-05-10T10:00:00+01:00 | Defines the end date of the promotion |
isActive | boolean | true | Not active promotions will not be applicable |
shopId | array | [ ”10001”, ”10002” ] | Defines in which applications the promotion will be available. You can add several applications IDs comma separated. |
companyId | array | [ ”1000” ] | Defines the company ID and is always related to the application ID. |
effect | object | { "id": "buy_x_get_y", "additionalData": { "variant_ids": [ 12389244, 23985437 ], "max_count": 1, "max_count_type": "per_eligible_items_quantity", "eligible_items_quantity": 6 } } | Defines the type of the promotion. |
effect.id | string | "id": "buy_x_get_y" | buy_x_get_y must be used for free gifts. automatic_discount must be used for relative or absolute reductions. |
effect.additionalData | object | "additionalData": { "variant_ids": [ 12389244, 23985437 ], "max_count": 1, "max_count_type": "per_eligible_items_quantity", "eligible_items_quantity": 6 } } | Depends on the effect.id. |
Optional parameters
Parameter | Type | Example | Definition |
---|---|---|---|
sibling-Promotions | object | "siblingPromotions": { "enabled": true, "allowList": [ "645e0c241a93369ff53f26e0", "646235bf496f8f56171c3762" ], "blockList": [ "64623787496f8f56171c3763" ], "level": "basket" } | You could have several applicable promotions for one basket. |
sibling-Promotions.enabled | boolean | true | You can only use block list or allow list; they are mutually exclusive. |
sibling-Promotions.allowList | array | [ "645e0c241a93369ff53f26e0", "646235bf496f8f56171c3762" ] | A list of promotions IDs that can be applied together with this promotion. |
sibling-Promotions.blocklist | array | [ "64623787496f8f56171c3763" ] | A list of promotions IDs that cannot be applied together with this promotion. |
sibling-Promotions.level | string | "level": "basket" | Defines on which level the promotions can be combined. |
audiences | object | "audiences": { "allowList": [ "645e0c241a93369ff53f26e0", "646235bf496f8f56171c3762" ], "blockList": [ "64623787496f8f56171c3763" ] } | Audiences defines for which customers the promotion is valid. Audiences can be set up in the SCAYLE Panel. |
audiences.allowList | array | "allowList": [ "645e0c241a93369ff53f26e0", "646235bf496f8f56171c3762" ] | The list of audience ids that can use this promotion. |
audiences.blocklist | array | "blockList": [ "64623787496f8f56171c3763" ] | The list of audience ids that can not use this promotion. |
globalConditions | array | "globalConditions": [ { "key": "mov_100", "condition": "payload.items.exists(i, 11003 in i.variant.id)" } ] | Defines the condition it self. |
globalConditions.key | string | "key": "mov_100" | Key of the condition. Can be used to identify which condition failed in the validation endpoint. |
globalConditions.condition | string | "condition": "payload.items.exists(i, 11003 in i.variant.id)" | Defines the condition it self. |
itemConditions | array | [ { "key": "mov_100", "condition": "item.color == 'yellow'" } ] | List of conditions that determines whether the promotion is applicable or not. Item conditions are order item related. |
itemConditions.key | string |
| Key of the condition. Can be used to identify which condition failed in the validation endpoint. |
itemConditions.condition | string | item.color == 'yellow' | Defines the condition it self. |
priority | string | "1" | In case several promotions are applicable but not combinable the priority decides. |
additionalData | object | { "variant_ids": [ 12389244, 23985437 ], "max_count": 1, "max_count_type": "per_eligible_items_quantity", "eligible_items_quantity": 6 } } | |
tiers | array | [ { "name": "Tier 1", "effect": { "additionalData": { "variant_ids": [ 12389244, 23985437 ], "max_count": 1 } }, "mov": 10000 } ] | Tierer promotions are minimum order value coupons:
|
Storefront API
Use the Storefront API to:
- fetch a list or specific promotions (also upcoming promotions)
In the SCAYLE Panel
You can manage Promotions in the SCAYLE Panel.
Use it to create, update and delete promotions.
SCAYLE Panel allows you to manage following Promotion types:
- Advanced
- Automatic discount
- Item Discount
- Buy X get Y
- Flash Sales
Additionally, you can manage:
- Price Campaigns
- Tiered Discounts
- Vouchers
It is not required to add a voucher code or similar in order to activate a promotion. The promotion is valid as soon as the promotion conditions are fulfilled.
Advanced promotions
Use one of our templates to create a promotion. By using the supported_effect
parameter, you can quickly create: