> ## Documentation Index
> Fetch the complete documentation index at: https://spreecommerce.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Promotions

> Learn about Spree's flexible promotion system for discounts, free shipping, and gifts.

## Overview

Promotions within Spree are used to provide discounts to orders, offer free shipping, or add items at no extra cost (e.g., free gifts). The promotion system is highly flexible, allowing you to create complex promotional campaigns based on various conditions.

### Promotion Model Diagram

```mermaid theme={"theme":"night-owl"}
erDiagram
    Promotion {
        string name
        string description
        string kind
        string code
        string path
        datetime starts_at
        datetime expires_at
        integer usage_limit
        string match_policy
        boolean advertise
    }

    PromotionRule {
        string type
        text preferences
    }

    PromotionAction {
        string type
        integer position
    }

    CouponCode {
        string code
        string state
    }

    OrderPromotion {
        integer order_id
        integer promotion_id
    }

    Adjustment {
        decimal amount
        string label
        boolean eligible
        string state
    }

    Promotion ||--o{ PromotionRule : "has many"
    Promotion ||--o{ PromotionAction : "has many"
    Promotion ||--o{ CouponCode : "has many"
    Promotion ||--o{ OrderPromotion : "has many"
    Promotion }o--o{ Store : "available in"
    PromotionRule }o--o{ Product : "applies to"
    PromotionRule }o--o{ Taxon : "applies to"
    PromotionRule }o--o{ User : "applies to"
    PromotionAction ||--o{ Adjustment : "creates"
    PromotionAction ||--|| Calculator : "has one"
    Order ||--o{ OrderPromotion : "has many"
    CouponCode }o--o| Order : "used by"
```

**Key relationships:**

* **Promotion** defines the campaign with rules and actions
* **Promotion Rules** determine eligibility conditions (FirstOrder, ItemTotal, Taxon, etc.)
* **Promotion Actions** define what happens when applied (discount, free shipping, free items)
* **Coupon Codes** track usage for code-based promotions
* **[Adjustments](/developer/core-concepts/adjustments)** are created on orders/line items to apply discounts

Promotions can be activated in two ways:

* **Automatic promotions** - Applied automatically when eligibility rules are met (e.g., free shipping on orders over \$50)
* **Coupon code promotions** - Applied when a customer enters a valid code during checkout

Promotions consist of two main components:

* **Rules** - Conditions that must be met for the promotion to apply
* **Actions** - What happens when the promotion is applied (discount, free shipping, etc.)

## Promotion Attributes

| Attribute      | Description                             | Example                  |
| -------------- | --------------------------------------- | ------------------------ |
| `name`         | The name of the promotion               | Summer Sale              |
| `description`  | Brief description (max 255 chars)       | 20% off all summer items |
| `kind`         | Type: `coupon_code` or `automatic`      | `automatic`              |
| `starts_at`    | When the promotion becomes active       | 2025-06-01 00:00:00      |
| `expires_at`   | When the promotion expires              | 2025-09-01 23:59:59      |
| `usage_limit`  | Max times the promotion can be used     | 500                      |
| `match_policy` | How rules are evaluated: `all` or `any` | `all`                    |
| `advertise`    | Whether to display on storefront        | `true`                   |
| `path`         | SEO-friendly URL path                   | `summer-sale`            |

### Multi-Code Promotions

For promotions that need unique codes per customer (e.g., influencer campaigns), Spree supports bulk code generation:

| Attribute         | Description                 | Example  |
| ----------------- | --------------------------- | -------- |
| `multi_codes`     | Enable bulk code generation | `true`   |
| `number_of_codes` | How many codes to generate  | 1000     |
| `code_prefix`     | Prefix for generated codes  | `SUMMER` |

Generated codes follow the pattern `{prefix}{random}`, e.g., `SUMMER22A0F62A230BD919`.

## Rules

Rules determine when a promotion is eligible. You can combine multiple rules and configure whether **all** rules must match or **any** rule is sufficient (via `match_policy`).

### FirstOrder

Applies only to a customer's first order. Checks both user account and email address to prevent abuse.

**Use case:** Welcome discount for new customers.

### ItemTotal

Requires the order subtotal to meet minimum and/or maximum thresholds.

**Configuration:**

* `preferred_amount_min` - Minimum order amount (default: 100.00)
* `preferred_operator_min` - Comparison operator: `gt` (greater than) or `gte` (greater than or equal)
* `preferred_amount_max` - Maximum order amount (optional)
* `preferred_operator_max` - Comparison operator: `lt` (less than) or `lte` (less than or equal)

**Use case:** "Free shipping on orders over $50", "10% off orders between $100-\$500".

### Product

Requires specific products to be in the order.

**Configuration:**

* `preferred_match_policy`:
  * `any` - At least one of the specified products
  * `all` - All specified products must be present
  * `none` - None of the specified products (exclusion)

**Use case:** "Buy Product A and get 20% off", "Discount excludes sale items".

### Taxon

Requires products from specific categories (taxons) to be in the order.

**Configuration:**

* `preferred_match_policy`: `any` or `all`

The rule automatically includes products in child taxons when a parent taxon is selected.

**Use case:** "20% off Electronics", "Buy from Shoes category get 10% off".

### User

Limits the promotion to specific customer accounts.

**Use case:** Employee discounts, VIP customer promotions.

### UserLoggedIn

Requires the customer to be logged in with an account.

**Use case:** Member-only discounts.

### OneUsePerUser

Ensures each customer can only use the promotion once.

**Use case:** One-time welcome offers, limited redemption campaigns.

### Country

Limits the promotion to orders shipping to a specific country.

**Configuration:**

* `preferred_country_id` or `preferred_country_iso` (ISO 2-letter code)

**Use case:** Regional promotions, country-specific campaigns.

### Currency

Limits the promotion to orders in a specific currency.

**Configuration:**

* `preferred_currency` - Currency code (e.g., "USD", "EUR")

**Use case:** Currency-specific pricing strategies.

### OptionValue

Requires products with specific option values (e.g., size, color) to be in the order.

**Configuration:**

* `preferred_eligible_values` - Array of eligible variant IDs

**Use case:** "10% off all red items", "Discount on size XL".

### CustomerGroup

Limits the promotion to customers belonging to specific customer groups.

**Configuration:**

* `preferred_customer_group_ids` - Array of customer group IDs

Customer groups are managed in Admin > Customers > Customer Groups and allow you to segment customers for targeted promotions.

**Use case:** VIP programs, loyalty tiers, wholesale pricing, B2B customer segments.

## Actions

Actions define what happens when a promotion is applied.

### CreateAdjustment

Creates a discount on the entire order total.

**Default calculator:** `FlatPercentItemTotal` (percentage off order)

**Available calculators:**

* `FlatPercentItemTotal` - Percentage off the order total
* `FlatRate` - Fixed amount off
* `FlexiRate` - First item at one rate, additional items at another
* `TieredFlatRate` - Different rates based on order total tiers
* `TieredPercent` - Different percentages based on order total tiers

**Use case:** "10% off your order", "$20 off orders over $100".

### CreateItemAdjustments

Creates discounts on individual line items. Only applies to items that match the promotion rules (e.g., items in a specific category).

**Default calculator:** `PercentOnLineItem` (percentage off each item)

The action respects rule actionability - if a Taxon rule specifies "Electronics", only electronics items receive the discount.

**Use case:** "15% off shoes", "Buy 2+ shirts get 10% off each".

### FreeShipping

Makes all shipments free by creating negative adjustments equal to shipping costs.

**Use case:** "Free shipping on orders over \$75", "Free shipping with code FREESHIP".

### CreateLineItems

Automatically adds specified products to the cart when the promotion is eligible.

**Configuration:**

* Map of variant IDs to quantities to add

The action checks stock availability before adding items. Items are not automatically removed if eligibility is lost - customers must remove them manually.

**Use case:** "Free gift with purchase", "Buy 2 get 1 free", "Spend \$100 get free sample".

## Coupon Codes

Coupon codes track promotion usage and can be single-use or multi-use.

### Single Code Promotions

Set the `code` attribute directly on the promotion. The `usage_limit` controls how many times it can be redeemed.

### Multi-Code Promotions

For bulk-generated codes, each code tracks its usage state:

| Attribute | Description     | Example                  |
| --------- | --------------- | ------------------------ |
| `code`    | The unique code | `SUMMER22A0F62A230BD919` |
| `state`   | Usage state     | `unused`, `used`         |

## Applying Coupon Codes via Store API

Customers apply coupon codes during checkout via the Store API:

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  // Apply a discount code to the cart
  const cart = await client.carts.discountCodes.apply('cart_abc123', 'SUMMER20', {
    spreeToken: '<token>',
  })

  // Remove a discount code from the cart
  await client.carts.discountCodes.remove('cart_abc123', 'SUMMER20', {
    spreeToken: '<token>',
  })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  # Apply a coupon code
  curl -X POST 'https://api.mystore.com/api/v3/store/carts/cart_abc123/coupon_codes' \
    -H 'Authorization: Bearer pk_xxx' \
    -H 'X-Spree-Token: <token>' \
    -H 'Content-Type: application/json' \
    -d '{ "code": "SUMMER20" }'
  ```
</CodeGroup>

Automatic promotions are applied without any customer action — they are evaluated on every order update.

## Promotion Flow

How promotions are evaluated and applied:

1. **Order Update** — When an order is updated, the system checks all eligible promotions
2. **Eligibility Check** — For each promotion:
   * Check if within `starts_at` and `expires_at` range
   * Check if under `usage_limit`
   * Evaluate all rules based on `match_policy` (all or any)
3. **Action Execution** — If eligible, each action is applied
4. **Tracking** — Applied promotions are recorded on the order
5. **Re-evaluation** — Eligibility is re-checked on every order update; adjustments from ineligible promotions are removed

## Related Documentation

* [Build Custom Promotion Rules & Actions](/developer/how-to/custom-promotion) - Step-by-step guide to creating custom rules and actions
* [Calculators](/developer/core-concepts/calculators) - Learn about promotion calculators
* [Orders](/developer/core-concepts/orders) - Understanding order processing
* [Customization Quickstart](/developer/customization/quickstart) - Overview of customization options
