Simulate and Apply Discounts
Discount simulation lets a retailer use Loyal Guru as a real-time promotion calculator. Before the customer confirms payment, the POS, e-commerce checkout, or mobile app can ask: "Which discounts would apply to this cart right now?"
This helps teams show savings before checkout, validate coupon codes, compare club prices, preview bundle mechanics, and verify whether stackability or limits change the final result. When the cart is confirmed, the same logic is applied with the real-time cart endpoint.
What you can simulateβ
| Simulation use case | What the response tells you |
|---|---|
| Automatic discounts | Which mass or club discounts apply without a code |
| Coupons and vouchers | Whether the submitted code is valid and which discount it unlocks |
| Bundles and BOGO | Whether the cart contains enough items to form each group |
| Stackability | Which campaigns win, stack, or are excluded by priority |
| Limits | Whether campaign caps, per-customer frequency, or per-transaction caps affect the result |
| Client vs LG calculation | Whether Loyal Guru modifies cart line values or only returns applicable promotions |
Endpoint summaryβ
| Endpoint | Purpose | Persisted? |
|---|---|---|
POST /carts/simulate | Preview discounts before payment confirmation | No |
POST /carts/realtime | Apply discounts to a confirmed cart | Yes |
Both endpoints use the same cart payload. The main difference is persistence: simulation returns the same kind of promotional answer but does not save the cart or consume vouchers.
Control discount applicationβ
Use apply_discounts to decide who performs the final price calculation:
| Value | Behavior |
|---|---|
true | Loyal Guru calculates the discount and returns adjusted cart values and effects[]. |
false | Loyal Guru returns which discounts apply, but the client system keeps responsibility for final price calculation. |
| omitted | The company-level default configuration is used. |
Use apply_discounts: true when Loyal Guru is the promo engine. Use apply_discounts: false when the POS or e-commerce system must calculate prices locally but still wants Loyal Guru to evaluate eligibility, coupons, vouchers, and campaign rules.
Control coupon and voucher applicationβ
Discount campaigns that are mass or loyalty-member promotions and do not require a coupon are included by default in every discount calculation. Use coupons_desired to decide which coupon-gated or voucher-gated discounts should also be evaluated.
coupons_desired value | Discount behavior |
|---|---|
"all" | Apply all mass and loyalty-member discounts without coupon, plus all vouchers assigned to the customer. |
"selected" | Apply all mass and loyalty-member discounts without coupon, plus only vouchers previously selected by the customer through the voucher selection flow. |
["SUMMER25", "34433"] | Apply all mass and loyalty-member discounts without coupon, plus the listed static coupon codes or unique voucher codes. |
[] or omitted | Apply only mass and loyalty-member discounts without coupon. No specific voucher or coupon is requested. |
This is how simulation can answer questions like "what happens if the customer applies this code?" or "what happens if all customer vouchers are considered?" The old vouchers_desired naming is deprecated; use coupons_desired.
When a coupon has auto redeem enabled, the customer does not need to manually type the code in the checkout experience. The cart request still decides the evaluation scope with coupons_desired: all assigned vouchers, selected vouchers, explicit codes, or no requested voucher.
Simulate a discountβ
POST /carts/simulate
X-Api-Key: your_api_key
X-Api-Secret: your_api_key_secret
X-Api-Version: 1
Content-Type: application/json
{
"id": 20260702002,
"customer_id": 1042,
"currency": "EUR",
"country": "ES",
"location_id": 12,
"apply_discounts": true,
"apply_points": false,
"coupons_desired": ["SUMMER25"],
"total": 42.80,
"lines": [
{
"product_id": "SKU-COFFEE-250",
"product_code": "COFFEE250",
"quantity": 2,
"unit_price": 6.50,
"total": 13.00,
"categories": ["beverages"]
},
{
"product_id": "SKU-CEREAL-500",
"product_code": "CEREAL500",
"quantity": 1,
"unit_price": 4.80,
"total": 4.80,
"categories": ["breakfast"]
}
]
}
To simulate every assigned voucher for the customer, use:
{
"id": 20260702002,
"customer_id": 1042,
"apply_discounts": true,
"coupons_desired": "all",
"total": 42.80,
"lines": [...]
}
Example response:
{
"id": 20260702002,
"apply_discounts": true,
"total": 36.50,
"effects": [
{
"rule_id": 3210,
"rule_name": "Club beverage discount",
"type": "discount",
"effectType": "percentage",
"distribution_type": "individual_items",
"value": -1.30,
"line": 1
},
{
"rule_id": 3399,
"rule_name": "SUMMER25 coupon",
"type": "discount",
"effectType": "direct_value",
"value": -5.00,
"coupon_info": {
"coupon_name": "SUMMER25",
"voucher_code": "SUMMER25"
}
}
]
}
Apply the discount to a confirmed cartβ
When the customer pays, submit the same cart to POST /carts/realtime.
POST /carts/realtime
X-Api-Key: your_api_key
X-Api-Secret: your_api_key_secret
X-Api-Version: 1
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
Use an Idempotency-Key when the POS or e-commerce checkout may retry after a timeout. This prevents the same cart from being processed twice.
How to read effects[]β
| Field | Meaning |
|---|---|
rule_id | Discount campaign that produced the effect |
rule_name | Campaign name |
effectType | Percentage, direct value, combo price, etc. |
distribution_type | How the discount is distributed across the cart |
line | Cart line affected, when the effect applies to a specific line |
coupon_info | Coupon or voucher details, when a code was involved |
If effects[] is empty, no discount qualified for that cart. Check audience, dates, currency, country, coupon/voucher code, conditions, limits, and stackability.