Skip to main content

Legacy Coupon Server

Legacy Coupon Server is for existing integrations that use the old coupon/voucher model. In this model, Loyal Guru does not act as the new discount engine. It serves coupon and voucher information, while the POS or external system applies the discount according to the coupon fields it receives.

When to use this page​

Use this guide only for companies that have not migrated their coupon integration to the current engine. New implementations should use New Engine Promo Engine or New Engine Coupon Server.

Responsibility split​

SystemResponsibility
Loyal GuruStores coupon/voucher state, exposes validation data, tracks selection/redemption/rollback depending on the integration.
POS / external systemInterprets coupon fields, validates any local pricing constraints, and applies the discount amount to the receipt.

Technical flow​

The legacy flow is POS-led. Loyal Guru validates and returns voucher data, but the POS compacts the returned vouchers, interprets the legacy coupon fields, and applies the discount on the receipt.

Voucher validation endpoints​

ScenarioEndpointPOS behavior
Customer identifies and wants to use selected vouchersGET /customers/{id}/vouchers/selectedRead the Customer's selected vouchers, compact the response, and decide which discounts can be applied locally.
Customer presents an individual coupon or voucher codeGET /vouchers/{code} with required customer_id and location_id query params (ValidateAVoucher operation)Validate the coupon/voucher data for that Customer and store, compact the returned voucher, and apply the discount locally using the key field.

The validation call always needs both the Customer and the location to resolve eligibility β€” this is the same pattern the current engine uses on GET /discounts (customer_id/customer_code plus location_id/location_code).

For endpoint schemas and HTTP behavior, use the API Reference.

Fields the POS must interpret​

Legacy coupons can include fields that determine how the POS should apply the benefit. The exact available fields depend on the legacy configuration, but integrations commonly need to handle:

  • Discount type and value: discount, discount_type.
  • Product or product-family restrictions: product_ids, excluded_product_ids, features (internal taxonomy), purchased_product_ids/purchased_affectation.
  • Store or country restrictions: location_ids.
  • Payment method restrictions: payment_methods, payment_method_categories_1/_2, payment_method_discount, payment_method_discount_type.
  • Validity dates and redemption limits: available_from, available_to, available_redemptions/available_redemtions, max_redemptions, min_money, max_money, min_units, max_units, cumulative.
  • Points-based vouchers: points, points_money, has_points.
  • Periodical-publication restrictions when configured for that company.
  • Voucher ownership (selected, frozen_redemptions) and redemption state (status, priority, applies_to) for targeted deliveries.
  • key: the field the POS uses to know which local discount logic to apply β€” not the same as the voucher code.

Legacy integrations may also read/write custom1–custom11 and custom1f–custom8f on the Customer profile. These are deprecated in favor of the attributes object β€” see Custom fields β†’ Attributes.

Voucher lifecycle endpoints​

Beyond read/validate, the legacy flow exposes the same generic voucher-lifecycle endpoints used across both engines (the vouchers entity is shared). These do not change when a company migrates to the new engine β€” only the campaign/eligibility read side changes (see How this differs from current engine).

Select / Deselect​

Selecting a voucher marks it so it is automatically applied on the Customer's next purchase; deselecting reverses that.

EndpointScopeUse it for
POST /vouchers/{code}/selectSingle voucherCustomer or POS explicitly opts in to use one voucher on the next purchase.
PUT /vouchers/selectBulk (max 50 vouchers per call, body { vouchers: [{ code }] })Pre-select a batch of vouchers, for example after a campaign delivery.
POST /vouchers/{code}/deselectSingle voucherCustomer or POS cancels the selection before redemption.
PUT /vouchers/deselectBulk (max 50 vouchers per call)Bulk-cancel selections.

GET /customers/{id}/vouchers/selected (see table above) is how the POS later reads which vouchers are currently selected for that Customer.

Freeze / Unfreeze​

Freezing puts a voucher on hold: a frozen voucher is not printed nor redeemable until it is unfrozen. Use it to protect a voucher that is in the middle of an incomplete transaction or under fraud review.

EndpointUse it for
POST /vouchers/{code}/freezeTemporarily block a voucher from being printed or redeemed.
POST /vouchers/{code}/unfreezeRelease the hold and make the voucher printable/redeemable again.

Rollback​

POST /vouchers/rollback reverts a redeemed voucher back to its previous state and increases available_redemptions by 1. It accepts a list, identifying each voucher either by id or by code + customer_id. It fails (400) when the voucher is not currently in redeemed status, has expired (voucher_expired), or its availability date is in the future (voucher_out_date).

Use this to undo a redemption after a cancelled sale, a failed payment, or a return β€” it is the legacy equivalent of the current engine's rollback step in the redeem/rollback pair.

Print​

POST /vouchers/print returns the batch of vouchers (or messages) the POS should print on the receipt for a given customer_id, location_id, and size. It supports exclude_codes (skip specific codes already handled), activity_id, and a debug flag to preview without marking vouchers as printed.

Ordering is fixed and always applied in this order:

  1. Campaign priority (if any) β€” campaigns with priority print first.
  2. Voucher priority within the same campaign (if any).
  3. Voucher availability β€” soonest to expire prints first.

By default, printing marks the vouchers as "printed" so the same batch is not returned again on the next call; use debug: true to inspect the batch without changing state. The response reuses the same field set described in Fields the POS must interpret (discount, discount_type, min_money/max_money, min_units/max_units, points, has_points, payment_methods, features, etc.).

How this differs from current engine​

TopicLegacy Coupon ServerCurrent Engine Promo Engine
Final discount calculationPOS/external systemLoyal Guru
Campaign rulesLegacy coupon fieldsrule_conditions, rule_application, rule_effects
Runtime cart evaluationNot the new discount enginePOST /carts/simulate / POST /carts/realtime
Recommended for new integrationsNoYes

Migration note​

When migrating from legacy coupon server to LE 2025, confirm whether the new target model is Promo Engine or Coupon Server. Do not map legacy coupon fields one-to-one without validating the new campaign rule model and voucher lifecycle.

Troubleshooting​

SymptomWhat to check
The POS cannot find selected vouchers for an identified CustomerConfirm the POS is sending the same Customer ID that owns the selected vouchers and that the vouchers are still active.
An individual coupon is returned but no discount is appliedCheck that the POS compacted the voucher response and mapped the legacy coupon fields to its local pricing rules.
Voucher validation succeeds but checkout redemption fails laterCheck voucher status, redemption limits, date window, store scope, and whether another checkout already consumed the voucher.
POS discount differs from Loyal Guru reportingConfirm that the POS applied the same legacy coupon fields that were returned during validation and sent the final usage/rollback state back to Loyal Guru.