Discount Calculation

Prev Next

The Promotion Engine evaluates all eligible promotions in a cart and applies them in a predefined order. This ensures that discounts are always calculated consistently, no matter how many promotions are active at the same time.

The calculation logic is used by both the /cart and /cart/finalize API endpoints, as well as the Promotion Calculator tool.

ℹ️ Tip: Before exploring this logic, it’s useful to understand the main promotion concepts (such as promotion types, discount types, and stacking rules) explained in the Configuring Promotions page.

Evaluation process

When a cart is calculated, the Promotion Engine reviews every active promotion to decide which ones to apply. It checks whether each promotion is:

  • Running: The promotion is within its defined start and end dates.

  • Valid: The cart matches any defined restrictions such as store group, currency, or or application limit.

  • Eligible: The cart meets all product or quantity conditions (e.g., required items or promo codes).

Once these promotions are identified, the engine determines which of them can be applied together. Promotions marked as exclusive are applied individually, while stackable ones can be combined and ordered according to their scope and discount type.

When several promotions are valid for the same cart, the engine automatically applies the combination that provides the highest total discount, always following the exclusivity and stacking rules.

Promotion application order

When multiple stackable promotions are valid for the same cart, the engine follows a clear order to ensure predictable results.

This order defines which promotions apply first, based on two dimensions:

  1. Scope: What part of the cart they affect (item, bundle, or cart level).

  2. Discount type: How the discount is calculated (fixed or percentage).

  1. Scope-based order

Scope order takes precedence over discount type order.

Discounts are applied from the smallest to the broadest scope.

  1. Item-level discounts (Promotional Pricing, Price Reduction, Cross-Selling, Buy X Get Y Free)

  2. Bundle / Product set-level discounts (Buy X for Total Y, Bundle)

  3. Cart-level discounts (Product Set, Promo Code)

  4. Item additions (Free Sample, Bonus Products)

Each promotion type operates at a specific scope level, defining how and where its discount is applied.

The engine always applies item- or bundle-level promotions before cart-level ones.

Cart-level promotions adjust the overall cart total, not individual item prices.

Minimum and maximum cart value restrictions are checked before promotions are applied and are not recalculated afterward. This prevents unexpected results when discounts significantly change the cart total.

  1. Discount type priority

Discount type order defines how different discount calculations are applied within the same scope.

Within each scope, discounts are applied in the following order:

  1. Fixed-amount discounts are applied first

  2. Percentage-based discounts are then calculated on the remaining price after fixed discounts

The /cart and /cart/finalize API endpoints return applied discounts in this same order (by scope first, then by discount type), ensuring consistent calculation results across all tools and integrations.

Examples

Example 1

Promo A: $50 off all T-shirts and footwear (bundle, fixed)
Promo B: 20% off all T-shirts and pants (bundle, percentage)

Cart:

  • 1 × white_tshirt (T-shirts category)

  • 1 × blue_jeans (Pants category)

  • 1 × sneakers (Footwear category)

Application logic:

  • The $50 fixed discount is applied first and split between the eligible T-shirt and footwear items.

  • Then, the 20% percentage discount is applied to the remaining value of the T-shirt and pants items.

The final cart total reflects both promotions, with the fixed discount applied before the percentage-based one.

Example 2

Promo A: $50 off cart total (cart-level, fixed)
Promo B: 20% off all T-shirts and pants (bundle, percentage)

Cart:

  • 1 × white_tshirt (T-shirts category)

  • 1 × blue_jeans (Pants category)

  • 1 × sneakers (Footwear category)

Application logic:

  • The 20% percentage discount is applied first to the eligible T-shirt and pants items, because item- and bundle-level promotions are always applied before cart-level ones.

  • Then, the $50 fixed discount is applied to the remaining cart total.

The final cart total reflects both discounts, with item-level discount applied before cart-level discounts.

Preventing negative prices

The Promotion Engine automatically prevents any product or cart value from being reduced below 0, even when multiple promotions apply. If the total discount value exceeds the basket value, the final price is capped at 0, ensuring consistent and realistic results.

Example

A promotion gives €60 off all T-shirts, and a T-shirt costs €40.

The final price is €0, not negative.

⚠️ Note: In some promotion combinations, applying a fixed discount followed by a promotion that sets a specific price for the same item may result in a higher final price than after the first discount.

This is expected behavior, as the second promotion redefines the item’s price rather than applying an additional reduction.

Testing and verification

The same calculation logic powers the Promotion Calculator, allowing you to test cart setups and confirm how promotions will behave before activating them in your live environment.