As e-commerce moves toward more flexible and personalized customer experiences, headless storefronts offer powerful advantages. This article explains how to integrate subscription-based products in a headless setup with Shopify, covering everything from data retrieval, cart creation, checkout redirection, and post-purchase subscription management.
Overview
A headless storefront separates the customer-facing front end from the backend commerce platform. It typically uses APIs to fetch product data, manage carts, trigger checkouts, etc. To add subscription capability in such a setup, you need to:
Store subscription options associated with products (Recurpay creates all selling plans on Shopify directly)
Fetch and display these on the storefront.
Let users select subscription frequency / plan.
Add subscription line items to cart (with correct plan IDs, discounts etc.).
Redirect to checkout to complete purchase.
Provide post-purchase management (subscriptions: pause, cancel, modify) via a customer portal
PRE PURCHASE FLOW
Step 1: Fetching Subscription Data for Products
If using Shopify’s Storefront API, you might query the product
or productVariant
nodes, fetch the related selling plans or plan groups. Example fields will include:
requiresSellingPlan
– if true, indicates a product can only be purchased as subscription, if false product can be purchased as both one time or subscriptionsellingPlanGroups
– groups of selling plans applying to a product.sellingPlans
– individual subscription plans with fields such as price adjustments (fixed or percentage), frequency, description, name.
Use this data to render subscription options in the UI: dropdowns, toggles ("one-time vs subscribe & save"), etc.
https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/products-collections/subscriptions#step-1-query-selling-plans-for-a-product
POST: https://{shop}.myshopify.com/api/{api_version}/graphql.json
Request
{
productByHandle(handle: "headless-product") {
id
variants(first: 5) {
edges {
node {
id
title
priceV2 {
amount
currencyCode
}
}
}
}
requiresSellingPlan
sellingPlanGroups(first: 1) {
edges {
node {
name
options {
name
values
}
sellingPlans(first: 10) {
edges {
node {
id
name
description
recurringDeliveries
priceAdjustments {
orderCount
adjustmentValue {
__typename
... on SellingPlanPercentagePriceAdjustment {
adjustmentPercentage
}
... on SellingPlanFixedAmountPriceAdjustment {
adjustmentAmount {
amount
currencyCode
}
}
... on SellingPlanFixedPriceAdjustment {
price {
amount
currencyCode
}
}
}
}
}
}
}
}
}
}
}
}
Response
"data": {
"productByHandle": {
"id": "a35lkOi8vc2hvcerjkhewrS9Qcm9jhrhwerbrbhjcjdfwerNjU=",
"variants": {
"edges": [{
"node": {
"id": "a35lkOi8vc2hvcerjkhewrS9Qcm9jhrhwerbrbhjcjdfwerNjU==",
"title": "Small",
"priceV2": {
"amount": "40.0",
"currencyCode": "USD"
}
}
},
{
"node": {
"id": "a35lkOi8vc2hvcerjkhewrS9Qcm9jhrhwerbrbhjcjdfwerNjU==",
"title": "Medium",
"priceV2": {
"amount": "70.0",
"currencyCode": "USD"
}
}
},
{
"node": {
"id": "a35lkOi8vc2hvcerjkhewrS9Qcm9jhrhwerbrbhjcjdfwerNjU==",
"title": "Large",
"priceV2": {
"amount": "90.0",
"currencyCode": "USD"
}
}
}
]
},
"requiresSellingPlan": false,
"sellingPlanGroups": {
"edges": [{
"node": {
"name": "Headless Product",
"options": [{
"name": "1 Month(s), 2 Month(s), 3 Month(s)",
"values": [
"1 Month(s)",
"2 Month(s)",
"3 Month(s)"
]
}],
"sellingPlans": {
"edges": [{
"node": {
"id": "a35lkOi8vc2hvcerjkhewrS9Qcm9jhrhwerbrbhjcjdfwerNjU==",
"name": "Deliver every 1 Month",
"description": null,
"recurringDeliveries": true,
"priceAdjustments": [{
"orderCount": null,
"adjustmentValue": {
"__typename": "SellingPlanPercentagePriceAdjustment",
"adjustmentPercentage": 15
}
}]
}
},
{
"node": {
"id": "a35lkOi8vc2hvcerjkhewrS9Qcm9jhrhwerbrbhjcjdfwerNjU==",
"name": "Deliver every 2 Months",
"description": null,
"recurringDeliveries": true,
"priceAdjustments": [{
"orderCount": null,
"adjustmentValue": {
"__typename": "SellingPlanPercentagePriceAdjustment",
"adjustmentPercentage": 10
}
}]
}
},
{
"node": {
"id": "a35lkOi8vc2hvcerjkhewrS9Qcm9jhrhwerbrbhjcjdfwerNjU==",
"name": "Delivery every 3 Months",
"description": null,
"recurringDeliveries": true,
"priceAdjustments": [{
"orderCount": null,
"adjustmentValue": {
"__typename": "SellingPlanPercentagePriceAdjustment",
"adjustmentPercentage": 10
}
}]
}
}
]
}
}
}]
}
}
}
}
Step 2: Creating a Cart with Subscription Items
Once a customer has selected a variant and a subscription plan:
Build the cart via API, adding line items which include both the variant (variant ID) and the plan ID (selling plan ID).
Also include quantity, and any other necessary metadata (e.g. delivery frequency etc.).
Ensure that price calculations reflect subscription discounts.
Because Shopify don’t allow you to directly initiate checkout with subscription items via the storefront API, you first create a cart, then use that to generate a checkout (or redirect link) pre-populated with the cart items.
POST: https://{shop}.myshopify.com/api/{api_version}/graphql.json
Request
mutation cartCreateMutation($cartInput: CartInput) {
cartCreate(input: $cartInput) {
cart {
id
lines(first: 250) {
edges {
node {
quantity
merchandise {
__typename
... on ProductVariant {
id
}
}
sellingPlanAllocation {
sellingPlan {
id
name
}
priceAdjustments {
price {
amount
}
compareAtPrice {
amount
}
perDeliveryPrice {
amount
}
}
}
}
}
}
}
}
}
Sample Variables
{
"cartInput": {
"lines": [
{
"quantity": 1,
"merchandiseId": "gid://shopify/ProductVariant/3",
"sellingPlanId": "gid://shopify/SellingPlan/2"
},
{
"quantity": 1,
"merchandiseId": "gid://shopify/ProductVariant/3"
}
]
}
}
Response
{
"data": {
"cartCreate": {
"cart": {
"id": "8a9des87d7f8s76a7s6d66f7s6",
"lines": [
{
"quantity": 1,
"merchandise": {
"__typename": "ProductVariant",
"id": "gid://shopify/ProductVariant/3"
},
"sellingPlanAllocation": {
"sellingPlan": {
"id": "gid://shopify/SellingPlan/2",
"name": "Delivery every 2 month"
},
"priceAdjustments": [
{
"price": {
"amount": "79.92"
},
"compareAtPrice": {
"amount": "120.0"
},
"perDeliveryPrice": {
"amount": "6.66"
}
}
]
}
}
]
}
}
}
}
Step 3: Redirecting to Shopify Checkout
After the cart is built in last step:
Generate a checkout link (or URL) using the cart ID.
Redirect the customer to the Shopify checkout page which is preloaded with the items (including the subscription line items).
The customer completes payment, shipping, etc., as with any other order.
Upon successful completion, the subscription is created both in Recurpay and Shopify.
POST: https://{shop}.myshopify.com/api/{api_version}/graphql.json
Request
query checkoutURL {
cart(id: "gid://shopify/Cart/8a9des87d7f8s76a7s6d66f7s6") {
checkoutUrl
}
}
Response
{
"data": {
"cart": {
"checkoutUrl": "https://recurpay.myshopify.com/cart/c/29567c413f68cf5e8c1cb623954f3a28"
}
}
}
Post-Purchase Subscription Management
An important part of the subscription experience is giving customers a way to manage (view, change, skip, pause/cancel) their subscription.
POST: https://{{recurpay_subdomain}}/api/storefront/v2/subscriptions/authenticate
Request
{
"customer_id": "3115083628619",
"email": "help@recurpay.com"
}
Response
{
"account": {
"url": "https://staging.recurpay.com/account/login/eyJpdiI6Inp6VEJmZEVmNGI3MHZYMEk4VVRBN0kVRVzFtV3Y2THd4K0p0ZkxIQT09IiwibWFjIjoiMTlhMDAwZjczMDE5ZDg5ZDVkMjQyMWIxZjMwYzFlNzQ1Mzc2NGQwMmFmZjUyNTZjOTc3MGZmMmRhMjAxNThiYyJ9eyJpdiI6Ink1QjlMd1ZUakx1aW1qOS9nc0RRcXc9PSIsInZhbHVlIjoiN25sZk52Q0"
}
}
Please redirect the customer to the url above. From there, they will be able to access their subscription portal, where they can view details, update payment information and manage everything related to their subscription.
Facing any issue with setting this up? Click the green chat button on Recurpay dashboard and we will get in touch with you or write us at help@recurpay.com