# Buy x pay y promotions

Commerce Layer provides a promotional engine built on top of two main resources: [promotions](https://docs.commercelayer.io/core-api-reference/promotions) and [promotion rules](https://docs.commercelayer.io/core-api-reference/promotion_rules).

When triggered, buy X pay Y promotions are responsible for adding a discount to the orders involved. The related discount amount is computed based on the associated SKU list: for each SKU in the order that belongs to the list and has a quantity equal to any multiple of the `x` attribute, a discount is applied as if the purchased quantity of the same SKU was decreased down to the same multiple of the `y` attribute. Basically, customers that add to cart a number greater than or equal to `n*x` (and less than `(n+1)*x`) units of a specific product pay only for `n*y` units of the same product, thus getting `n*(x-y)` units for free — where `x` must be greater than `y` (and `n` greater than zero). The corresponding stock is updated consistently (i.e. decreased by `n*x` units).

{% hint style="info" %}
In order for buy X pay Y promotions to apply to [bundles](https://docs.commercelayer.io/core-api-reference/bundles), the resources must share the same [SKU list](https://docs.commercelayer.io/core-api-reference/sku_lists) (in this case, there is no SKUs partial matching).
{% endhint %}

Let's consider an example where a buy X pay Y promotion (with **X=3** and **Y=2**) is associated with an SKU list containing the products A, B, and C. Some of the possible scenarios are the following:

* If customers add to cart **3** units of product A, they pay for **2** and get **1** of them for free.
* If customers add to cart **6** units of product A and **3** units of product B, they get **2** units of product A and **1** unit of product B for free.
* If customers add to cart **7** units of product A, **4** units of product B, and **2** units of product C, they get **2** units of product A and **1** unit of product B for free.
* If customers add to cart **5** units of product A, **2** units of product B, and **8** units of product D (which is not in the associated SKU list), they get **1** unit of product A for free.
* If customers add to cart **2** units of product A and **4** units of product D (which is not in the associated SKU list), the promotion doesn't apply and they get no discount.

## Cheapest free

If you set the `cheapest_free` attribute to `true` (default is `false`) the buy X pay Y promotion type behaves differently. In this case, the value of the `x` attribute is matched against the sum of the quantities of *all* the SKUs in the associated list. If the order contains some of the SKU belonging to the list and the sum of their quantity is equal to any multiple of `x` (i.e. `n*x`), the customer will pay only for the most expensive `n*y`, thus getting the `n*(x-y)` cheapest ones among those SKUs for free.

Considering the same example as above in the case of a *cheapest free* buy X pay Y promotion (let's assume that A is the most expensive and C the cheapest of the three products), the aforementioned scenarios could now lead to different discounts:

* If customers add to cart **3** units of product A, they pay for **2** and get **1** of them for free.
* If customers add to cart **6** units of product A and **3** units of product B (**9** units of products belonging to the list in total), they get all **3** units of product B for free.
* If customers add to cart **7** units of product A, **4** units of product B, and **2** units of product C (**13** units of products belonging to the list in total), they get **2** units of product B and all **2** units of product C for free (**4** units for free in total).
* If customers add to cart **5** units of product A, **2** units of product B, and **8** units of product D (**7** units of products belonging to the list in total), they get all **2** the units of the product B for free.
* If customers add to cart **2** units of product A and **4** units of product D (**2** units of products belonging to the list in total), the promotion doesn't apply and they get no discount.

## Application scope

Buy X pay Y promotions can be optionally defined by currency code or restricted to a specific active market (in the latter case the currency code is inherited by the market's price list). Within the time window given by their activation and expiration dates, buy X pay Y promotions that have not reached their total usage limit are considered active. If no promotion rule is associated with an active buy X pay Y promotion, the discount is applied to:

* All the orders, if the promotion is not restricted to a specific currency or market.
* All the orders in the specified currency, if a currency code is specified but the promotion is not restricted to a specific market.
* All the orders of the market in scope, if the promotion is attached to a market.

Otherwise, if one or more promotion rules are defined, the promotion is triggered only when it matches all of them.

{% hint style="info" %}
Multiple buy X pay Y promotions can be applied to the same order, even concurrently with other promotion types (based on their [priority](https://docs.commercelayer.io/core-api-reference/promotions#priority-and-order-of-application) and up to the involved items amount [saturation](https://docs.commercelayer.io/core-api-reference/promotions#discount-distribution)), as long as you don't reach the maximum number of active promotions allowed for your organization.
{% endhint %}

## Discount calculation and distribution

The total discount due to buy X pay Y promotions is calculated and distributed on the matching line items of type `skus` or `bundles` belonging to the associated SKU list, according to the promotion logic.
