Documentation Index Fetch the complete documentation index at: https://mintlify.com/Shopify/subscriptions-reference-app/llms.txt
Use this file to discover all available pages before exploring further.
POS Extension
The POS (Point of Sale) extension enables retail staff to create and manage subscription orders directly from Shopify POS. This extension provides multiple UI components that integrate subscription functionality into the point of sale workflow, allowing in-person subscription sales.
Extension Configuration
extensions/pos-extension/shopify.extension.toml
api_version = "2025-10"
[[ extensions ]]
type = "ui_extension"
name = "pos-extension"
handle = "pos-extension"
description = "Subscriptions"
[[ extensions . targeting ]]
module = "./src/MenuItemModal.tsx"
target = "pos.cart.line-item-details.action.render"
[[ extensions . targeting ]]
module = "./src/MenuItem.tsx"
target = "pos.cart.line-item-details.action.menu-item.render"
[[ extensions . targeting ]]
module = "./src/Tile.tsx"
target = "pos.home.tile.render"
[[ extensions . targeting ]]
module = "./src/TileModal.tsx"
target = "pos.home.modal.render"
Extension Targets
The POS extension integrates at four key touchpoints:
Cart Line Item Menu Target : pos.cart.line-item-details.action.menu-item.renderAdds a “Subscriptions” button to cart line item action menus
Line Item Modal Target : pos.cart.line-item-details.action.renderFull modal for selecting subscription options on cart items
Home Tile Target : pos.home.tile.renderDashboard tile on POS home screen for quick access
Home Modal Target : pos.home.modal.renderModal opened from home tile for subscription management
Components
Home Tile
Displays subscription information on the POS home screen:
extensions/pos-extension/src/Tile.tsx
import { render } from 'preact' ;
import { useSellingPlanTile } from './hooks/useSellingPlanTile' ;
import I18nProvider from './components/I18nProvider' ;
import i18n from './i18n/config' ;
const TileComponent = () => {
const { title , subtitle , enabled , disabledReason , onCartChange } =
useSellingPlanTile (
shopify . cart . current . value ,
i18n ,
shopify . session . currentSession . posVersion ,
);
shopify . cart . current . subscribe (( cart ) => {
onCartChange ( cart );
});
return (
< s-tile
heading = { title }
subheading = { subtitle }
onClick = { () => {
shopify . action . presentModal ();
} }
disabled = { ! enabled }
data-testid = "subscription-tile"
data-disabled-reason = { disabledReason }
/>
);
};
export default async () => {
render (
< I18nProvider locale = { shopify . locale } >
< TileComponent />
</ I18nProvider > ,
document . body ,
);
};
Adds subscription action to cart line items:
extensions/pos-extension/src/MenuItem.tsx
import { render } from 'preact' ;
import I18nProvider from './components/I18nProvider' ;
import { MINIMUM_VERSION_SUPPORTED } from './constants/constants' ;
import { isVersionSupported } from './utils/versionComparison' ;
const ButtonComponent = () => {
const handleButtonPress = () => {
shopify . action . presentModal ();
};
const versionSupported = isVersionSupported (
shopify . session . currentSession . posVersion ,
MINIMUM_VERSION_SUPPORTED ,
);
const hasSellingPlanGroups = shopify . cartLineItem ?. hasSellingPlanGroups ;
const enabled = hasSellingPlanGroups && versionSupported ;
const disabledReason = ! versionSupported
? 'version-unsupported'
: ! hasSellingPlanGroups
? 'feature-disabled'
: null ;
return (
< s-button
onClick = { handleButtonPress }
disabled = { ! enabled }
variant = "secondary"
data-testid = "subscription-menu-item"
data-disabled-reason = { disabledReason }
/>
);
};
export default async () => {
render (
< I18nProvider locale = { shopify . locale } > ,
< ButtonComponent />
</ I18nProvider > ,
document . body ,
);
};
Version Support
The extension checks POS version compatibility:
extensions/pos-extension/src/constants/constants.ts
export const MINIMUM_VERSION_SUPPORTED = '10.14.0' ;
extensions/pos-extension/src/utils/versionComparison.ts
export function isVersionSupported (
currentVersion : string ,
minimumVersion : string
) : boolean {
const current = currentVersion . split ( '.' ). map ( Number );
const minimum = minimumVersion . split ( '.' ). map ( Number );
for ( let i = 0 ; i < 3 ; i ++ ) {
if ( current [ i ] > minimum [ i ]) return true ;
if ( current [ i ] < minimum [ i ]) return false ;
}
return true ;
}
Features
Subscription Selection
Staff can select subscription options for products in the cart:
Add Product to Cart
Staff adds a subscription-eligible product to the cart
Open Line Item Actions
Tap on the cart line item to open actions menu
Select Subscription
Choose “Subscriptions” from the menu
Choose Plan
Select delivery frequency and any discount options
Apply to Cart
Subscription is applied to the line item
Cart Integration
The extension monitors cart state:
shopify . cart . current . subscribe (( cart ) => {
// Check if cart has subscription-eligible items
const hasEligibleItems = cart . lineItems . some (
item => item . hasSellingPlanGroups
);
// Update tile state
updateTileStatus ( hasEligibleItems );
});
Selling Plan Selection
Display available selling plans for a product:
interface SellingPlanGroup {
id : string ;
name : string ;
sellingPlans : SellingPlan [];
}
interface SellingPlan {
id : string ;
name : string ;
description : string ;
billingPolicy : {
interval : 'DAY' | 'WEEK' | 'MONTH' | 'YEAR' ;
intervalCount : number ;
};
pricingPolicy : {
adjustmentType : 'PERCENTAGE' | 'FIXED_AMOUNT' | 'PRICE' ;
adjustmentValue : number ;
};
}
POS-Specific Components
The extension uses POS-specific Smart Grid components:
s-tile
s-button
s-modal
s-list
< s-tile
heading = "Subscriptions"
subheading = "Manage subscription items"
onClick = { handleClick }
disabled = { false }
/>
< s-button
onClick = { handleClick }
variant = "primary"
disabled = { false }
>
Add Subscription
</ s-button >
< s-modal
title = "Select Subscription"
onClose = { handleClose }
>
{ /* Modal content */ }
</ s-modal >
< s-list >
{ sellingPlans . map ( plan => (
< s-list-item
key = { plan . id }
onClick = { () => selectPlan ( plan ) }
>
{ plan . name }
</ s-list-item >
)) }
</ s-list >
Modal Implementation
The line item modal allows selling plan selection:
extensions/pos-extension/src/MenuItemModal.tsx
import { render } from 'preact' ;
import { useState } from 'preact/hooks' ;
const MenuItemModal = () => {
const [ selectedPlan , setSelectedPlan ] = useState ( null );
const cartLineItem = shopify . cartLineItem ;
const sellingPlanGroups = cartLineItem ?. sellingPlanGroups || [];
const handleSelectPlan = async ( planId : string ) => {
setSelectedPlan ( planId );
// Apply selling plan to line item
await shopify . cart . applySellingPlan ({
lineItemId: cartLineItem . id ,
sellingPlanId: planId ,
});
shopify . action . dismissModal ();
};
return (
< s-modal title = "Select Subscription" >
< s-list >
{ sellingPlanGroups . map ( group => (
< div key = { group . id } >
< s-heading > { group . name } </ s-heading >
{ group . sellingPlans . map ( plan => (
< s-list-item
key = { plan . id }
onClick = { () => handleSelectPlan ( plan . id ) }
selected = { selectedPlan === plan . id }
>
< s-stack direction = "vertical" >
< s-text weight = "bold" > { plan . name } </ s-text >
< s-text size = "small" > { plan . description } </ s-text >
</ s-stack >
</ s-list-item >
)) }
</ div >
)) }
</ s-list >
</ s-modal >
);
};
Tile Modal
The home screen tile opens a modal with subscription management:
extensions/pos-extension/src/TileModal.tsx
const TileModal = () => {
const cart = shopify . cart . current . value ;
const subscriptionItems = cart . lineItems . filter (
item => item . sellingPlanAllocation
);
return (
< s-modal title = "Subscription Items" >
{ subscriptionItems . length === 0 ? (
< s-text > No subscription items in cart </ s-text >
) : (
< s-list >
{ subscriptionItems . map ( item => (
< s-list-item key = { item . id } >
< s-stack direction = "horizontal" spacing = "base" >
< s-image src = { item . image } size = "small" />
< s-stack direction = "vertical" >
< s-text weight = "bold" > { item . title } </ s-text >
< s-text size = "small" >
{ item . sellingPlanAllocation . sellingPlan . name }
</ s-text >
</ s-stack >
</ s-stack >
</ s-list-item >
)) }
</ s-list >
) }
</ s-modal >
);
};
Localization
Support multiple languages for POS staff:
extensions/pos-extension/locales/en.json
{
"tile" : {
"title" : "Subscriptions" ,
"subtitle" : "Manage subscription items" ,
"noItems" : "No subscription items"
},
"modal" : {
"title" : "Select Subscription" ,
"apply" : "Apply" ,
"cancel" : "Cancel"
},
"menuItem" : {
"label" : "Subscriptions"
},
"errors" : {
"versionUnsupported" : "POS version not supported" ,
"noPlansAvailable" : "No subscription plans available"
}
}
Error Handling
Handle common POS scenarios:
if ( ! versionSupported ) {
return (
< s - banner tone = "warning" >
This feature requires POS version { MINIMUM_VERSION_SUPPORTED } or higher .
Current version : { currentVersion }
</ s - banner >
);
}
if ( ! hasSellingPlanGroups ) {
return (
< s - banner tone = "info" >
This product doesn 't have subscription options available .
</ s - banner >
);
}
Testing
Test the POS extension on actual POS devices or the POS simulator:
Test Scenarios
Version Compatibility : Test on minimum and latest POS versions
Cart States : Empty cart, cart with eligible/ineligible items
Network Issues : Handle offline mode and API failures
Multiple Selling Plans : Products with single and multiple plan groups
Mixed Cart : Cart with subscription and one-time purchase items
Best Practices
Clear Labeling Use clear, concise labels for subscription options visible on small screens
Quick Selection Optimize for speed - retail staff need quick workflows
Visual Feedback Show immediate confirmation when subscription is applied
Error Prevention Disable options that aren’t available rather than showing errors
Offline Support
POS extensions should handle offline scenarios:
if ( ! navigator . onLine ) {
// Show cached subscription options
const cachedPlans = localStorage . getItem ( 'sellingPlans' );
if ( cachedPlans ) {
return JSON . parse ( cachedPlans );
}
// Queue for sync when online
queueOfflineAction ({
type: 'APPLY_SELLING_PLAN' ,
lineItemId ,
sellingPlanId ,
});
}
Customization Examples
Custom Tile Styling
const getTileAppearance = ( cartState ) => {
const subscriptionCount = cartState . lineItems . filter (
item => item . sellingPlanAllocation
). length ;
return {
heading: 'Subscriptions' ,
subheading: subscriptionCount > 0
? ` ${ subscriptionCount } subscription items`
: 'Add subscription items' ,
variant: subscriptionCount > 0 ? 'primary' : 'secondary' ,
};
};
Plan Recommendations
const getRecommendedPlan = ( sellingPlans : SellingPlan []) => {
// Recommend most frequent billing for retail
return sellingPlans . sort (( a , b ) => {
const aDays = intervalToDays ( a . billingPolicy );
const bDays = intervalToDays ( b . billingPolicy );
return aDays - bDays ;
})[ 0 ];
};
Admin Actions Create selling plan groups available in POS
Buyer Subscriptions Customer portal for managing POS-created subscriptions
Requirements
POS Version : 10.14.0 or higher
Hardware : Compatible POS devices (iPad, Android tablets)
Network : Internet connection for initial setup (offline support for operations)
Permissions : Staff must have cart modification permissions