Promotions

Promotions

The Promotions API can be used to create, update and query Promotions and Promo Codes.

Promotions are Lightspeed Retail (X-Series)'s easy-to-use discounting tool for running in-store discounts and sales. Promotions can apply several types of offers, such as 20% off all Nike shoes, and give retailers, developers and integrations the flexibility to manage Promotions programmatically via the Lightspeed Retail (X-Series) API.

Promotions are complex and have the potential to impact a retailer's revenue, so we recommended thoroughly reviewing the overview of setting up Promotions.

Supported Workflows

  • Create a Promotion - this endpoint creates a new Promotion. It responds with the newly-created Promotion, including the Promotion's ID. See the Promotion object below, for configuring Promotion types.
  • List Promotions - this endpoint is for listing Promotions. Allows for optional filtering/pagination by end date and page size.
  • Get a Promotion - this endpoint returns a single Promotion by ID.
  • Update a Promotion - this endpoint updates an existing Promotion by ID. All of a Promotion's fields except its ID may be updated. There are no partial updates. All fields must be specified in the update. The response contains the updated Promotion object.
  • Adding Promo Codes: During Create or Update (above), you can optionally add Promo Codes to the Promotion, using "add_promo_code": [...] and "set_promo_code": true
  • 'Delete' a Promotion - this is achieved by updating a Promotion with "status": "archived". Archived Promotions are not returned by the list Promotions endpoint but can be retrieved by getting them by ID
  • Delete Promo Codes: You can only delete a promo code which has not been redeemed yet - the endpoint will return an array of promo codes for which deletion was not possible.
  • Ending a Promotion early: Update the Promotion with an end_time in the past.

Applying discounts

Discounts are applied automatically as part of a sale.

Applying discounts to external sales

An integration or add-on could also apply discounts to line items, via the API.

  • The discounts endpoint accepts a sale, with metadata, and will return any matching Promotions that apply. The sale is also returned, with applicable discounts specified for each line item.
  • Despite its POST method, this endpoint doesn't actually modify any server-side state.
  • It's the client's responsibility to pass along the full details of the sale, including all customer and product information (product type, tags, etc).

The Promotion object

There are several types of Promotion. Promotions are configurable using their Condition and Action. Each promotion can have one Condition and one Action.

The advanced Promotion options that Lightspeed Retail (X-Series) offers are explained in detail in this help center article.

Name and Description

A Promotion has a name field and optional description field which are for display purposes only and don't affect the functionality of the Promotion.

Time

A Promotion has start_time and end_time fields that define a continuous time range during which the Promotion applies. end_time may be null which creates an open-ended range, so that a Promotion never ends.

Times are specified in UTC, using an RFC3339 format, without a timezone component - for example, 2019-11-01T05:39:15

Example date match rule

{
  "name": "Time example",
  ...
  "start_time": "2019-11-01T05:39:15",
  "end_time": "2020-10-01T05:39:15"
  ...
}

Channel, Outlet, and Customer Group

The Promotion structure contains three fields which are arrays of strings: channels, outlet_ids, and customer_group_ids. These fields are optional and each will default to an empty array when not provided. When a sale is submitted to Promotions, it contains exactly one channel, one outlet ID and one customer group ID.

  • Outlets can be retrieved from the Outlets API
  • Channels can be set to either "Register" for in-store only, "Ecommerce" for online (Lightspeed Retail (X-Series) e-commerce) only, or empty for both. outlet_ids and customer_group_ids are referenced using their UUIDs.
  • Customer groups can be managed using the Customer Groups API

Example Promotion:

{
  "name": "Example",
  ...
  "channels": ["Register"],
  "outlet_ids": ["02e60bb7-8de1-11e9-f4c2-ca031b9cba97"],
  "customer_group_ids": ["02e60bb7-8de1-11e9-f4c2-ca02a315894f", "02e60bb7-8de1-11e9-f4c2-ca02a7141ffe"],
  ...
}

The Promotion above applies in-store only, at the outlet with ID 02e60bb7-8de1-11e9-f4c2-ca031b9cba97, and for either the customer group with ID 02e60bb7-8de1-11e9-f4c2-ca02a315894f or the ID 02e60bb7-8de1-11e9-f4c2-ca02a7141ffe. The condition will also have to pass, and we'll talk about that next.

Conditions

The condition field in the Promotion structure checks whether the products in a sale meet the criteria necessary to trigger a Promotion. There are several types of conditions with varying structures. A condition always has a type field and can have include and exclude fields that help it determine which products are part of the Promotion. If a condition passes, the Promotion's action applies a discount.

Types of Conditions

Product Set

A product_set condition accepts certain types of products based on a quantity and a set of include/exclude criteria.

{
  "type": "product_set",
  "quantity": 1,
  "include": [],
  "exclude": []
}

The condition passes if there are at least quantity items in the sale that meet the include/exclude criteria.

If you want a Promotion to apply to all products and have no quantity restrictions, specify quantity as 1 and leave include and exclude empty, just as in the sample above.

We also allow a quantity range to be specified. For example

{
  "type": "product_set",
  "min_quantity": 2,
  "max_quantity": 4,
  "include": [],
  "exclude": []
}

This condition passes when 2-4 of any items are purchased. The min_quantity and the max_quantity fields can't be used at the same time as the quantity field, otherwise the API will return a 422 error response

Sale Price

A sale_price condition sums up the prices of certain products and passes if that sum meets or exceeds min_price.

{
  "type": "sale_price",
  "min_price": 200,
  "include": [],
  "exclude": []
}

The example condition above passes when the sale total is at least $200.

Including and Excluding Products

Many conditions have include and exclude fields that allow the condition to pass only for certain criteria. The include array is an array of filters that specify which criteria to include and the exclude array is an array of filters that specify which criteria to exclude. Includes are evaluated first, followed by excludes.

Each filter is a JSON object with exactly two fields: field and value. Example:

{
  "field": "brand_id",
  "value": "02e60bb7-8de1-11e9-f4c2-b314f7db985c"
}

The field specifies which product field to match on and the value specifies which value to match. So the example above would filter the product with the brand_id 02e60bb7-8de1-11e9-f4c2-b314f7db985c. Available fields are:

  • brand_id - The product's brand ID
  • supplier_id - The product's supplier ID
  • tag_id - Any tags applied to the product (by ID)
  • type_id - The product's type ID
  • variant_parent_id - The product's variant parent ID or its own ID

Actions

Once it's determined that a Promotion's condition passes and the sale in question meets other criteria (channel, outlet, customer group), the Promotion's action is applied to the sale. Like condition, the structure of action varies, but the type field is always available.

Types of Actions

Basic Percent Discount

Apply a percentage discount to all the items that fulfilled the condition's filter. An example of this Promotion might be 20% off products of a certain brand.

{
  "type": "basic_percent_discount",
  "value": 0.20
}
Basic Fixed Discount

Apply a fixed price discount to all the items that fulfilled the condition's filter. An example of this Promotion might be $5 off all items with a certain tag.

{
  "type": "basic_fixed_discount",
  "value": 5
}
Percent Discount

Apply a percentage discount action to N number of items per condition fulfilled. N is equal to the quantity field.

An example of this Promotion is "Buy 2 t-shirts, Get 2 t-shirts at 50%", this mean for every two t-shirts you buy, you can get two additional t-shirts at a 50% discount

{
  "type": "percent_discount",
  "value": 0.50,
  "quantity": 2,
  "include": [],
  "exclude": []
}
Fixed Discount

Apply a fixed discount action to N number of items per condition fulfilled. N is equal to the quantity field.

An example of this Promotion is "Spend $200 on shirts, Get $20 off a pair of pants", this means for every $200 you spend on shirts, you can get a pair of pants for $20 off

{
  "type": "fixed_discount",
  "value": 20,
  "quantity": 1,
  "include": [],
  "exclude": []
}
Percent Pool Discount

Apply a fixed percentage discount action spread across a pool of line items based on the action filter. An example of this Promotion is "Spend $100 and get 10% off all sale items"

{
  "type": "percent_pool_discount",
  "value": 0.1,
  "include": [],
  "exclude": []
}
Fixed Pool Discount

Apply a fixed amount discount spread across a pool of line items based on the action filter. An example of this Promotion is "Spend $100 and get $10 off all sale items"

{
  "type": "fixed_pool_discount",
  "value": 10,
  "include": [],
  "exclude": []
}
Fixed Price Discount

Apply a fixed price discount on a set of items. For example "Buy 3 packs of Tim Tams for 5 dollars"

{
  "type": "fixed_price_discount",
  "value": 5
}
Loyalty

The loyalty action type is basically a do-nothing action. It's used when the Promotion is only intended to affect loyalty points using a loyalty_multiplier as a multiplier. For example, you might use a "loyalty" action with a multiplier` of 2 if you want to run a "double loyalty" Promotion.

{
  "type": "loyalty"
}

Loyalty Multiplier

The loyalty_multiplier field is used to multiply loyalty when a Promotion is applied. This can be used in the loyalty action above, but may also be used to disallow or reduce loyalty for Promotions by setting it to 0. loyalty_multiplier is optional and its default is 1.

Status

The status field is used to indicate whether the Promotion is active or archived. When the Promotion is active, it can be retrieved by calling /promotions or /promotions/:id. Active Promotions will be used to apply discount(s) to a sale when they're within the date range of the Promotion. Archived Promotions can't be retrieved from the /promotions endpoint however they can be retrieved from the promotions/:id endpoint. Archived promotions aren't used to apply discount(s).