Shopify App Billing Demystified: Navigating Payments for Your SaaS Integration
Hey there, fellow builders and innovators in the Shopify ecosystem! We've all been there: you've built an amazing web app or SaaS, you're ready to integrate with Shopify, and then… BAM! You hit a wall with payment requirements. I've seen this exact scenario play out countless times in the Shopify community forums, and a recent thread titled "Shopify apps and payment" really highlighted this common confusion.
Our friend Prabhav2 kicked off the discussion, grappling with app rejections because their existing web app uses Razorpay, but Shopify kept pushing for "Shopify payment" when connecting their platform. It's a classic case of mixing up different payment flows, and honestly, it's an easy trap to fall into if you don't know the nuances.
Untangling the Payment Maze: App Fees vs. Customer Orders
The core of the confusion, as EverythingDSM wisely pointed out early in the thread, often lies in distinguishing what exactly Razorpay (or your chosen payment gateway) is collecting payment for. Are we talking about:
- Your app/SaaS subscription fees? This is what merchants pay you for using your app.
- The Shopify merchant's customer orders? This is what the merchant's shoppers pay them for products on their store.
These are two entirely different beasts, and Shopify's rules apply very differently to each. The App Review team, as Taha_Dev and One-Sun1995 clarified, is primarily concerned with the first one: how your app charges merchants.
If you're distributing your Shopify integration through the Shopify App Store, Shopify has a strict requirement: any charges associated with that app must go through Shopify App Pricing or the Shopify Billing API. You simply can't send Shopify merchants off to Razorpay (or Stripe, or PayPal) to pay for access to an app they found and installed via Shopify.
Your Dual Billing Path Solution
So, what's the workaround? The consensus from the community is clear: you need a dual billing path. This means your backend needs to be smart enough to know where a merchant came from and route their billing accordingly.
1. For Shopify App Store Installs: Shopify Billing is Non-Negotiable
If a merchant installs your app directly from the Shopify App Store (or via an install link that initiates the Shopify OAuth flow), their app subscription payments absolutely must go through Shopify's system. Here's how to tackle it:
- Define your plans: Set up your app's pricing plans either via the Partner Dashboard's Shopify App Pricing (which gives you a hosted plan picker page within the Shopify admin) or by using the Shopify Billing API's
appSubscriptionCreateif you need a custom plan UI. - Merchant approval: Ensure the merchant approves the charge directly inside their Shopify Admin. This is crucial for transparency and for Shopify to track and refund charges if needed.
- Feature unlock: Your app then unlocks features based on the active subscription status received from Shopify.
- Block Razorpay access: This is perhaps the most critical part: a merchant who installs from Shopify must never be able to reach your Razorpay checkout, pricing page, or upgrade buttons. As Taha_Dev emphasized, reviewers click around – hiding a button isn't enough. Keep the non-Shopify billing logic completely separate for Shopify-origin accounts.
Here's a snippet of server-side logic Taha_Dev shared to help enforce this:
// Run once when a shop is connected to an account. Store the result and never switch it automatically.
function resolveBillingRail(account, connectedAt) {
const paidBeforeC === 'active' &&
account.firstRazorpayPaymentAt &&
account.firstRazorpayPaymentAt < connectedAt;
return paidBeforeConnect ? 'razorpay' : 'shopify';
}
// Server-side guard on every Razorpay route: checkout, plans, upgrade, billing portal
function requireRazorpayRail(req, res, next) {
if (req.account.billingRail !== 'razorpay') return res.status(403).end();
next();
}
And if you're using Shopify App Pricing, you'll direct Shopify-rail accounts to Shopify's hosted plan page, which looks something like this:
https://admin.shopify.com/store/{store_handle}/charges/{app_handle}/pricing_plans
2. For Standalone Web App Sign-ups: Razorpay Can Stay
Great news! Your existing Razorpay setup is perfectly fine for customers who sign up directly on your standalone web app and aren't coming through the Shopify App Store. Connecting their Shopify store does not automatically force them to switch their existing SaaS checkout to Shopify Payments.
3. Handling Existing Customers Who Later Connect Shopify
This is where it gets a little nuanced, but the community has some clear guidance. If a merchant was already a paying Razorpay customer with an active subscription before they connected their Shopify store, Shopify generally doesn't require you to migrate that existing contract to Shopify Billing. The key is to tie this to a genuine, pre-existing paid relationship, not just a free account. Make sure your logic prevents double-billing!
However, if they had a free or trial account on your site and then connect Shopify, or if they arrive from the App Store, they should be treated as Shopify-origin and any upgrade should go through Shopify billing.
Streamlining Your Shopify Integration Flow
Beyond billing, the thread also touched on the overall install path, which is crucial for app review success:
- Start from Shopify: When a merchant connects Shopify from your web app, don't ask for their
myshopify.comdomain (Requirement 2.3.1). Instead, send them to your App Store listing or an install link so the process starts on Shopify's end. - OAuth first: Ensure the OAuth flow runs immediately, before any of your signup or UI screens (2.3.2), and again on reinstall (2.3.4).
- Land in your app: After approving scopes, the merchant should land directly in your app UI (2.3.3).
- Flexible plans: Merchants must be able to upgrade or downgrade their paid plans without needing to contact you directly (1.2.2, 1.2.3).
Tips for a Smooth App Review (and Resubmission!)
If your app has been suspended, like Divyan154's was, don't despair. Here's how to get back on track:
- Resubmit from Partner Dashboard: You can typically resubmit on the date shown in your app's status banner.
- Clear testing instructions: At the top of your testing instructions, clearly explain what you've changed. Explicitly state that Razorpay is only for customers who paid you before connecting Shopify, and it's completely unreachable by Shopify-origin installs.
- Comprehensive screencast: Provide a screencast that demonstrates the full flow: installing from Shopify, going through OAuth, landing in your app's UI, upgrading via Shopify's plan or charge approval, and even uninstalling and reinstalling. If you're maintaining the existing-customer Razorpay path, show that separately with working test credentials.
- Be honest about exemptions: Do not tick "I have approval to charge merchants outside of the Shopify Billing API" unless Shopify has explicitly granted you an exemption. These are rare and usually for very specific pricing models Shopify Billing can't support.
- Reach out if stuck: If a suspension seems unusually long or you're hitting repeated roadblocks, don't hesitate to contact Partner Support through the help center.
The key takeaway from this whole discussion is that Shopify's App Store requirements are there to ensure a consistent, transparent experience for merchants. By implementing a clear distinction between how you bill your app users (via Shopify for App Store installs) and how your standalone customers pay you (via Razorpay), you can successfully navigate the review process and get your fantastic app into the hands of more Shopify store owners!