In this tutorial we will go over how to create new discounts on the fly from within your Shopify App. We're going to go through using Ruby with an example Ruby on Rails app. If you are not familiar with Shopify app development check out out our article on Setting Up a Shopify Embedded App with Rails.

1. The Anatomy of a Discount

When we talk about discounts in the context of the Admin API they can be broken down into 2 resources: PriceRule and DiscountCode.

Price Rules

More info and documentation for price rules

Before creating a discount code you must create a price rule. High level, price rules allow you to define how and when discounts can be applied and what the value of the discount is.

An example POST to create a price rule that will give a customer a one-time 20% discount off a whole order would look like this:


{
  "price_rule": {
    "title": "20OFF", 
    "target_type": "line_item", 
    "target_selection": "all", 
    "allocation_method": "across", 
    "value_type": "percentage", 
    "value": "-20.0", 
    "customer_selection": "all", 
    "start_time": Time.now.iso8601, 
    "usage_limit": 1
  }
}

The PriceRule resource let's you define the parameters for a discount, but you need to actually create associated discount codes for customers to use.

Discount Codes:

More information and documentation for DiscountCode

The DiscountCode resource lets you create new codes associated with an existing price rule.

To create a new discount code associated with our 20OFF price rule we would POST the following to /admin/price_rules/#{price_rule_id}/discount_codes.json


{
  "discount_code": {
    "code": "20OFF4U"
  }
}

Now we will have a discount code 20OFF4U that can be used once to redeem 20% off an entire purchase.

2. Create a Dsicount Code in Your App

Set up a controller for Discount Codes

We are going to start by setting up a controller to manage our discount code creation.


# app/controllers/discounts_controller.rb
class DiscountsController < ApplicationController

end

create a route for your new discounts controller action


#config/routes.rb
post 'discounts', to: 'discounts#create' 

Instantiate new Shopify API session in the discounts controller

This assumes you are using the shopify_app gem and have stored the shop related data for each shop your app is loaded on in a Shops table as generated by the gem.

Behind the scenes the shopify_app gem relies on the shopify_api gem to facilitate setting up API sessions and making requests.

To initiate a new Shopify API session for the appropriate shop we are going to need to rely on some parameters passed back from our request. Specifically we will pass back the myshopify.com domain in a param named shop. On the controller side it will look like this:


# app/controllers/discounts_controller.rb
class DiscountsController < ApplicationController
  def create
    #using the shop param grab the appropriate shop from the DB
    shop = Shop.where(shopify_domain: params[:shop]).first

    ## create new shopify API session
    session = ShopifyAPI::Session.new(shop.shopify_domain, shop.shopify_token)
    ShopifyAPI::Base.activate_session(session)

    #create a new price rule
    @price_rule = ShopifyAPI::PriceRule.create(
      title: "CrumbDiscount",
      target_type: "line_item",
      target_selection: "all",
      allocation_method: "across",
      value_type: "percentage",
      value: "-20.0",
      customer_selection: "all",
      starts_at: Time.now.iso8601, 
      usage_limit: 1
    )

    #create a new discount code
    discount_code = ShopifyAPI::DiscountCode.new
    discount_code.prefix_options[:price_rule_id] = @price_rule.id
    discount_code.code = "20Off#{rand(10 ** 10)}"
    discount_code.save
    render json: discount_code
  end
end

Dynamically determine the value of the discount

We recently built an app where a user action helped determine the value of the discount. We can slightly modify our controller to allow for a discount value param and discount title param to customize these discounts even further


# app/controllers/discounts_controller.rb
class DiscountsController < ApplicationController
  def create
    #using the shop param grab the appropriate shop from the DB
    shop = Shop.where(shopify_domain: params[:shop]).first

    ## create new shopify API session
    session = ShopifyAPI::Session.new(shop.shopify_domain, shop.shopify_token)
    ShopifyAPI::Base.activate_session(session)

    #create a new price rule
    @price_rule = ShopifyAPI::PriceRule.create(
      title: "CrumbDiscount",
      target_type: "line_item",
      target_selection: "all",
      allocation_method: "across",
      value_type: "percentage",
      value: "-#{params[:discount_value]}",
      customer_selection: "all",
      starts_at: Time.now.iso8601, 
      usage_limit: 1
    )

    #create a new discount code
    discount_code = ShopifyAPI::DiscountCode.new
    discount_code.prefix_options[:price_rule_id] = @price_rule.id
    discount_code.code = params[:discount_title]
    discount_code.save
    render json: discount_code
  end
end

A sample request

To tie it all together, if I wanted to make a discount code client side the request would look something like this:


fetch('https://your-app-url.com/discounts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': Rails.csrfToken()
  },
  body: JSON.stringify({discount_value: '15.0', shop:'whatever-shop.myshopify.com', discount_title: 'UniqueDiscountName'})
})
.then(res => res.json())
.then(resp => alert(`Your discount code is ${resp.code}`))