Skip to main content

Overview

A promotion is a campaign: a percentage off, free shipping, or free items in the cart. Rules decide when it applies, actions decide what it does. A promotion is a rule that exists on its own, set up in advance and lasting across many orders. What lands on any one order is a Discount — the record of money actually coming off. The promotion is the campaign; the discount is what a particular customer got. Promotions can be activated in two ways:
  • Automatic promotions — applied on their own when the rules are met (e.g. free shipping on orders over $50)
  • Coupon code promotions — applied when a customer enters a valid code during checkout

When promotions compete

Several promotions can qualify for the same item at once. Spree applies only the one that saves the customer the most, and records just that one. Losing candidates aren’t stored or tracked — they’re simply reconsidered on every cart change. So a promotion that loses today can win tomorrow, when the basket changes, without any bookkeeping to keep straight. What an applied promotion leaves behind on the order is a Discount — a permanent record that survives the promotion being edited or deleted.

Promotion Attributes

Multi-Code Promotions

For promotions that need unique codes per customer (e.g. influencer campaigns), Spree supports bulk code generation: Generated codes follow the pattern {prefix}{random}, e.g. SUMMER22A0F62A230BD919.

Rules

Rules decide when a promotion is eligible. You can combine multiple rules and configure whether all must match or any is enough (via match_policy). You can also build your own rules for business-specific conditions.

Actions

Actions define what happens when a promotion applies.

Order discount (CreateAdjustment)

A discount on the whole order. The amount is distributed proportionally across the line items — there is no single order-level row, so per-item reporting and partial returns always know their share. Default calculator: FlatPercentItemTotal (percentage off the order). Also available: FlatRate, FlexiRate, TieredFlatRate, TieredPercent. Use case: “10% off your order”, “$20 off orders over $100”.

Item discount (CreateItemAdjustments)

A discount on individual line items. Only items that match the promotion’s rules receive it — if a Category rule says “Electronics”, only electronics are discounted. Default calculator: PercentOnLineItem (percentage off each item). Use case: “15% off shoes”, “Buy 2+ shirts get 10% off each”.

Free shipping (FreeShipping)

Writes a discount on each fulfillment covering its delivery cost. The row is kept even when the cost is zero — its presence is what marks the order as having free shipping. Use case: “Free shipping on orders over $75”, “Free shipping with code FREESHIP”.

Free items (CreateLineItems)

Adds specified products to the cart when the promotion is eligible, checking stock first, and discounts them to zero. A customer who already has the gift in their cart gets theirs free rather than a duplicate; any further copies they bought stay paid for. The gift is taken back when the promotion stops applying. No second action is needed to make the gift free — pairing this with an order discount set to the gift’s price discounts it twice. Use case: “Free gift with purchase”, “Spend $100 get a free sample”.

Managing Promotions

Create and manage promotions via the Admin API. Rules and actions can be supplied inline on create — each is a { type, preferences } draft using the rule and action types described above:
You can also add rules and actions to an existing promotion, or update and remove the promotion itself:
The available rule and action types — including any custom ones you register — are discoverable at /api/v3/admin/promotion_rules/types and /api/v3/admin/promotion_actions/types, together with their preference schemas. The dashboard’s promotion editor is built on these endpoints, so custom types show up there without any UI work.
Deleting a promotion doesn’t disturb the orders that used it. Their discount rows stay, keeping the code and value they were created with — only the link back to the promotion is cleared.

Coupon Codes

Coupon codes track promotion usage and can be single-use or multi-use.
  • Single code — set the code attribute on the promotion; usage_limit controls how many times it can be redeemed.
  • Multi-code — bulk-generated codes each track their own state (unused / used). A code is used up only when an order is placed with it. Applying it to a cart just holds it there, and a shopper who presents a code held by an abandoned cart takes it over, so an unfinished checkout never burns a code.
Customers apply codes on the cart via the Store API:
The returned cart already carries the updated discounts and totals. If the cart doesn’t qualify yet — say the code needs a $100 minimum and the cart holds $80 — the code stays on the cart and the discount activates on its own the moment the cart qualifies. Automatic promotions need no customer action at all — they are evaluated on every cart change.

Promotion Flow

  1. Cart change — every change to a cart (item added, address entered, code applied) triggers a recalculation
  2. Eligibility — each connected promotion is checked: active dates, usage limits, then rules per match_policy
  3. Competition — candidate discounts are computed for every eligible promotion; per item, per fulfillment, and order-wide, the largest saving wins
  4. Persistence — winning discounts are written as rows; anything stale from the previous pass is removed; tax is then estimated on the discounted amounts
  5. Placement — once the order is placed, its discount rows are frozen; usage counts are recorded against the promotion