Quick Nav
- Why checkout conditions stopped scaling
- Setup burden, hosting and event controls at a glance
- Voucherify: one eligibility decision across channels
- Talon.One: rule depth against discovery cost
- Stripe promotion codes beside the invoice
- commercetools: predicates, precedence and the cart
- Shopify discounts and versioned extensions
- Saleor: GraphQL checkout and event observability
- Medusa: flexibility you operate yourself
- The release gate before real codes go live
- Choosing the system that already owns the decision
Why checkout conditions stopped scaling
Discount logic used to live wherever the payment button lived. In the hosted-button era an _xclick form carried a hard price, and "20% off" meant a second button with a second price. Carts arrived, and the logic moved into checkout conditionals: total above a threshold, customer group matching, date earlier than the campaign end.
That arrangement survives exactly as long as one storefront exists.
Add a mobile app, an assisted-sales desk and a marketplace feed, and the same rule gets re-implemented three times with three subtly different answers. Reusable rules, customer eligibility, per-customer and campaign-wide limits, stacking policy and auditability all become expensive to maintain inside storefront code, because none of them have a single home.
The useful move is to break the coupon path into four separately evidenced decisions: campaign configuration, checkout-time validation, redemption recording, and refund reconciliation. A reusable promotion record then needs a rule identifier, an active interval, an eligible customer or segment, product or cart conditions, per-customer and campaign-wide limits, a stacking policy, and redemption state.
Scope matters here. This comparison covers developer-facing promotion components only. Email marketing and loyalty accounting platforms were excluded because they never own the checkout validation path; the boundary is the pre-payment discount decision, and post-purchase messaging does not establish whether the checkout total is correct.
Setup burden, hosting and event controls at a glance
| Engine | Setup burden | Hosting model | Rule flexibility | Event controls to verify | Best architectural fit |
|---|---|---|---|---|---|
| Voucherify | Integration requiring customer and catalogue mapping | Managed service | High, outside the commerce platform | Signatures, retries, replay, idempotency keys, delivery logs | Cross-channel promotion governance |
| Talon.One | Integration requiring customer and catalogue mapping | Managed service | Layered eligibility across many attributes | Synchronous session evaluation plus asynchronous delivery logs | Multi-attribute campaign governance |
| Stripe | Direct configuration | Managed service | Bounded to payment and subscription objects | Signature verification, duplicate handling, reconciliation | Billing-led discounts |
| commercetools | Integration requiring commerce-service ownership | Managed composable platform | Predicate-driven cart discounts with precedence | Cart and order events, delivery logs | Stacks where commercetools owns the cart |
| Shopify | Direct configuration for codes; extension work for custom logic | Hosted platform | Plan- and API-dependent | Catalogue sync and order reporting webhooks | Stores already on Shopify |
| Saleor | Integration requiring commerce-service ownership | Self-operated or managed | Channel- and variant-aware | Payload capture, delivery status, retries, replay | Headless GraphQL commerce |
| Medusa | Integration requiring commerce-service ownership | Self-operated | Custom modules and workflows | Workflow events, retries, rollback | Engineering-operated headless stacks |
Every row should also state which systems supply cart, customer and product data, because that is where the integration hours actually go. Webhook capability was recorded through observable mechanisms only: signature verification, retry policy, a replay route, idempotency keys and a delivery log. Assumed uptime is not a control.
One qualifier I'd attach to this table: no capability above is labelled tested, because the brief supplied no named technical reviewer or execution record. Confirm each cell against current product documentation within one to five business days before you commit.
Voucherify: one eligibility decision across channels
This suits teams that want promotions, validation rules and redemption tracking sitting outside the commerce platform. The integration sequence is predictable: stable product and customer identifiers first, then checkout validation and redemption, then order, cancellation and refund events.
Map catalogue identifiers, customer attributes, cart lines, currency, channel and order status before configuring a single campaign. Validation and redemption must carry the same cart and customer keys, or reconciliation becomes guesswork.
Pilot design: 7–14 days containing one targeted offer, one per-customer limit, one global limit, one cancellation and one refund. Recheck quotas, feature gates and plan requirements within one to five business days of implementation approval.
Talon.One: rule depth against discovery cost
Deep rule modelling earns its keep when eligibility is layered across customer tiers, product attributes and behavioural signals. The cost is discovery. Inventory the cart, customer, product and behavioural attributes available at decision time, then restrict the rule model to fields with a defined owner and update path.
A discovery worksheet should record each attribute's source, type, null handling and refresh point. Test at least one absent customer attribute, one stale product attribute and two simultaneously eligible campaigns.
Keep the two clocks apart. Synchronous session evaluation drives the checkout price decision; asynchronous events serve analytics, fulfilment and reconciliation. Exercise synchronous calls for 30–60 minutes under expected checkout concurrency, then watch asynchronous delivery and replay for 24–72 hours, recording request latency separately from webhook delivery delay.
Stripe promotion codes beside the invoice
When billing or checkout already runs through Stripe, coupons and customer-facing promotion codes attach to objects you are managing anyway. Integration is comparatively direct for payment-led offers and comparatively poor for catalogue or merchandising logic.
Contract tests should cover a fixed-duration subscription discount, a repeating discount, a code restricted to one customer, an expired code, and an attempted second redemption where limits apply.
The assessment stops at transactions and subscriptions managed by the same payment platform. Catalogue-wide merchandising, cross-platform carts and externally priced orders need rule ownership elsewhere.
commercetools: predicates, precedence and the cart
Assess this one from the cart outward. Product data, channels and customer groups feed predicates; cart discounts perform the calculation; discount codes supply controlled activation. Predicate modelling, ordering and stacking deserve attention before anyone builds redemption reporting.
Build fixtures for two matching cart discounts with different precedence, two channels with different eligibility, a product variant missing a referenced attribute, and a cart modified after code entry. Run acceptance and margin checks across a 7–21 day proof of concept, capturing submitted code, rejection reason, calculated discount, tax basis, final cart total and gross-margin guardrail for every fixture.
Architectural fit is strongest where commercetools already owns the cart. Adopting the platform purely for coupon handling needs a much broader business case.
Shopify discounts and versioned extensions
Split the work in two. Ordinary code administration is quick; executable custom discount logic depends on store setup, current API releases and plan-level capabilities. Checkout calculation stays in the platform's discount path, and webhooks handle catalogue synchronisation, order reporting and reconciliation rather than executing the discount.
Test one amount-off code, one product-scoped code, one minimum-purchase condition, one combination conflict and one order edit or refund. Record the API version and deployed function or extension version beside each result. After adopting a new API release or changing discount extensions, complete regression checks within 5–10 business days, including one checkout created before deployment and one created after.
Saleor: GraphQL checkout and event observability
For headless builds on GraphQL, the data contract comes first: channels, currencies, product variants, customer identity and checkout lines aligned before any promotion behaviour is exercised.
Maintain fixtures for two channels, two currencies, one unavailable variant, one anonymous checkout promoted to an authenticated customer, and one promotion ending while a checkout remains open. Pin the deployed server and schema versions for a 14–28 day experiment, and inside that window force one receiver timeout, one non-success response and one duplicate event, then verify alerts and replay behaviour against the version actually running.
Medusa: flexibility you operate yourself
Separate the synchronous cart calculation from the workflows and events that maintain surrounding state. Promotion flexibility only counts as an advantage once ownership is assigned for application deployment, data migration, queue or event processing, checkout alerts and module upgrades. Each custom promotion rule also needs a versioned test fixture.
Run a 7–14 day staging exercise covering one successful workflow, one failed step, one retry, one rollback and one upgrade rehearsal. Inject checkout delays of 250 milliseconds, 1 second and 3 seconds, and watch what the customer sees at each.
The release gate before real codes go live
Order the gate by failure risk: deterministic rule fixtures first, checkout contract and concurrency tests second, event recovery third, controlled commercial measurement last.
- Mandatory fixtures: precedence, stacking, expiry from 23:55 to 00:05 in the configured time zone, customer eligibility, per-customer and global limits, refund, partial return, and two concurrent redemption attempts.
- Contract tests: valid, invalid, expired and already-redeemed codes, with timeout injections at 250 milliseconds, 1 second and 3 seconds.
- Event recovery: signatures, duplicate events, reversed ordering, retries and replay across 24–72 hours.
- Commercial measurement: promotion exposure, accepted-code count, invalid-code reason, checkout completion, order value and contribution margin over a 14–28 day controlled comparison.
Invalid-code reasons repay close reading. Scoring rejected entries against live codes by Levenshtein distance separates shoppers who mistyped from shoppers who were handed the wrong code, and those two problems have entirely different fixes.
Document whether checkout fails open or closed, and keep a rollback procedure executable within one deployment window.
Choosing the system that already owns the decision
Select from the system that already owns the decision. Payment platforms for billing-led discounts. The hosted store for platform-native discounts. The cart service for cart-native rules. A dedicated promotion API for cross-channel governance. An engineering-operated stack for highly customised headless flows.
The decision record must name the owner of synchronous checkout latency, event replay, campaign approval, reconciliation and rollback, then stay open for 2–5 business days after the final failure drill so unresolved defects get reviewed rather than quietly closed.
If you keep one fixture from this entire comparison, keep the expiry test that spans 23:55 to 00:05 in the configured time zone. Ten minutes of wall clock, straddling midnight, is where precedence, time zones and redemption state all fail at once.







