For E-Commerce stores that offer subscription-based products, ReCharge is a powerful application for handling recurring payments and orders. However, ReCharge does not automatically sync discount codes from your Shopify admin, meaning discount codes from your Shopify admin will not automatically register on your ReCharge theme pages.
ReCharge offers a manual way to sync discounts through their web UI, but this can be time consuming for an advanced discount code system. For example, say your site auto-generates discounts for customers with a certain level of loyalty points, and you want these discounts to be available on subscriptions in real-time.
My Solution:
Understanding Shopify
discounts/create
WebhookUnderstanding Shopify and ReCharge API Endpoints
Set Up AWS Lambda and API Gateway
Write Lambda Function Code
Connect your Lambda Function to
discounts/create
The Discounts/Create Webhook
Shopify has a plethora of webhooks, one of them being for the event disocunts/create
. This webhook will send a JSON payload to a specified URL. See more Shopify webhooks here
In this tutorial, we will utilize this webhook payload to trigger a AWS lambda function (or any hosted function provider of your choice), that will then make an API call to add this discount to ReCharge.
To clarify before we begin, the discounts that I will be syncing will only be for x% off
or $x off
. You can easily apply the same concept to specific item discounts, read here to see more information on ReCharge's discount
object.
Shopify and ReCharge Endpoints
Now let's go over the endpoints you will need, and what they accomplish.
Endpoint | Function |
/admin/api/2024-01/graphql.json | General-purpose endpoint for Shopify Admin GraphQL requests. |
api.rechargeapps.com/discounts | ReCharge endpoint that we will use to create discounts |
Now we can derive a gameplan using the webhook and these API endpoints, on how we can sync these discounts.
Set up
discounts/create
webhook to send payload to our cloud function (AWS Lambda, in my case)Within cloud function, make a GraphQL request to get all of the necessary information regarding this newly created discount
Then, make a POST request to ReCharge API to add this discount to ReCharge.
Set Up AWS Lambda and API Gateway
If you are not using AWS for your cloud function and API gateway, feel free to skip this step. Just make sure that your cloud function can be triggered by a POST request to an endpoint. This function will be triggered by the Shopify discounts/create
webhook.
In AWS, you want to connect your Lambda function to an API endpoint. I suggest you use API Gateway, a native AWS service. This will allow you to trigger this Lambda function via POST request, and the setup is rather easy.
Here is the official AWS tutorial for accomplishing this. If you have some experience with AWS already, this should be trivial.
Connect your Lambda Function to discounts/create
Now we need to let Shopify know where to send the discount payload when a new discount is created.
Go to your Shopify Admin page
Go to Settings > Notifications > Webhooks
Select 'Create Webhook'
Select 'Discount Creation' for the Event field
Enter the API endpoint to your cloud function in the 'URL' field
Here is an example payload your function will receive:
{
"admin_graphql_api_id": "gid://shopify/DiscountAutomaticNode/1",
"title": "Automatic free shipping",
"status": "ACTIVE",
"created_at": "2016-08-29T08:00:00-04:00",
"updated_at": "2016-08-29T08:00:00-04:00"
}
Write Lambda Function Code
Now that we have the webhook sending the above payload to your cloud function, we need to write the cloud function. I will be using Python, since I found it the easiest for this application. Node.js or any other scripting language available should be fine.
import json
import os
import re
import urllib.request
import urllib.parse
from datetime import datetime, timedelta
def lambda_handler(event, context):
shopify_graphql_url = "https://sizzlefish.myshopify.com/admin/api/2024-01/graphql.json"
shopify_access_token = os.environ['SHOPIFY_ACCESS_TOKEN']
recharge_api_url = "https://api.rechargeapps.com/discounts"
recharge_access_token = os.environ['RECHARGE_ACCESS_TOKEN']
# Extract data from the incoming event
body = event.get("body")
if isinstance(body, str):
data = json.loads(body)
else:
data = body # Assume it's already a dict if not a string
discount_code = data.get("title")
if not discount_code:
return {
"statusCode": 400,
"body": json.dumps({"message": "Discount code (title) not found in the event body"})
}
# Step 1: Query Shopify GraphQL API to get discount details
query = f"""
query {{
codeDiscountNodeByCode(code: "{discount_code}") {{
id
codeDiscount {{
__typename
... on DiscountCodeBasic {{
title
status
createdAt
codeCount
shortSummary
discountClass
endsAt
}}
}}
}}
}}
"""
headers = {
"X-Shopify-Access-Token": shopify_access_token,
"Content-Type": "application/json"
}
# Create the request for Shopify API
shopify_request = urllib.request.Request(
shopify_graphql_url,
data=json.dumps({"query": query}).encode('utf-8'),
headers=headers
)
try:
with urllib.request.urlopen(shopify_request) as response:
response_body = response.read().decode('utf-8')
shopify_data = json.loads(response_body)
except urllib.error.HTTPError as e:
return {
"statusCode": e.code,
"body": json.dumps({"message": "Error querying Shopify API", "details": e.read().decode('utf-8')})
}
print(shopify_data)
code_discount = shopify_data.get("data", {}).get("codeDiscountNodeByCode", {}).get("codeDiscount", {})
short_summary = code_discount.get("shortSummary", "")
if "0.01" in short_summary:
return {
"statusCode": 200,
"body": json.dumps({"message": "Discount not created due to shortSummary containing '0.01'"})
}
# Step 2: Extract value and value_type from shortSummary
value = None
value_type = None
# Match percentage-based discount (e.g., "20% off")
percentage_match = re.search(r'(\d+)% off', short_summary)
if percentage_match:
value = percentage_match.group(1)
value_type = "percentage"
# Match amount-based discount (e.g., "$10 off")
amount_match = re.search(r'\$(\d+\.?\d*) off', short_summary)
if amount_match:
value = amount_match.group(1)
value_type = "fixed_amount"
# If value and value_type could not be determined, return an error
if not value or not value_type:
return {
"statusCode": 400,
"body": json.dumps({"message": "Could not parse value and value_type from shortSummary"})
}
# Calculate the ends_at date (e.g., 30 days from now)
current_time = datetime.utcnow()
ends_at = current_time + timedelta(days=30)
ends_at_str = ends_at.strftime('%Y-%m-%dT%H:%M:%SZ')
# Step 3: Create the discount in Recharge
recharge_payload = {
"applies_to": {
"purchase_item_type": "ALL"
},
"channel_settings": {
"api": {
"can_apply": True
},
"checkout_page": {
"can_apply": True
},
"customer_portal": {
"can_apply": True
},
"merchant_portal": {
"can_apply": True
}
},
"code": discount_code,
"status": "enabled",
"usage_limits": {
"first_time_customer_restriction": False,
"one_application_per_customer": False
},
"value": value,
"value_type": value_type,
"ends_at": ends_at_str
}
recharge_headers = {
"Content-Type": "application/json",
"X-Recharge-Version": "2021-11",
"X-Recharge-Access-Token": recharge_access_token
}
# Create the request for Recharge API
recharge_request = urllib.request.Request(
recharge_api_url,
data=json.dumps(recharge_payload).encode('utf-8'),
headers=recharge_headers
)
try:
with urllib.request.urlopen(recharge_request) as response:
if response.status != 201:
return {
"statusCode": response.status,
"body": json.dumps({"message": "Error creating discount in Recharge", "details": response.read().decode('utf-8')})
}
except urllib.error.HTTPError as e:
return {
"statusCode": e.code,
"body": json.dumps({"message": "Error creating discount in Recharge", "details": e.read().decode('utf-8')})
}
return {
"statusCode": 200,
"body": json.dumps({"message": "Discount created successfully in Recharge"})
}
This code looks much more complicated than it is. This python script does the following 3 things:
Unpacks incoming payload of created discount
Gets more info about the discount using Shopify GraphQL API
Adds the discount to our ReCharge account
Conclusion
Now, discounts will automatically sync from your Shopify admin into ReCharge, increasing quality-of-life for both developers and customers alike. Now, when a customer receives an automatically generated discount code from a loyalty rewards system, it will also be available for subscription-based products. And next time you are manually creating discounts, you only have to create them within Shopify and let our cloud function do the rest!