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 DiscountCodeThe 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
🔥 TIP - For now, our discounts controller will inherit from the Application controller. If you were creating discounts inside of an embedded app you may want to use the Shopify Authenticated Controller. Otherwise it would be a good idea to implement some type of API authentication so not just anyone can post and create discounts in your app.
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
🔥 TIP - discount codes should be unique ❄️
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}`))