Shopify App Billing Demystified: Payments for Your App vs. Your Web App

Hey everyone,

Ever felt like you’re trying to untangle a knot when it comes to Shopify app payments? You’re definitely not alone. I’ve seen this confusion pop up time and again in the community, and it was the central theme of a really helpful discussion recently, kicked off by Prabhav2. They were hitting a wall with their app getting rejected because Shopify kept asking them to use 'Shopify payment' even though their existing web app relies on Razorpay. It’s a classic mix-up, and honestly, it’s easy to get these wires crossed.

The core of the issue, as EverythingDSM wisely pointed out, boils down to understanding two very different payment systems:

The Big Picture: Two Payment Worlds

Think of it this way: there’s the money your merchants pay YOU for your app or SaaS subscription, and then there’s the money your merchants’ customers pay THEM for store orders. Shopify’s App Review team is only concerned with the first one when it comes to your app’s approval.

When Shopify’s reviewers say you need to use “Shopify payment” for your app, they don't mean you need to replace your entire Razorpay system for your standalone web app. As Taha_Dev clarified in a helpful response to Prabhav2, they're referring to Shopify App Pricing or the Shopify Billing API. This is how your app charges the merchant for its services. Razorpay, Stripe, PayPal – these are fine for your standalone web app’s customers, but not for merchants who discover and install your app through the Shopify App Store.

Why the Strict Rules for App Store Billing?

One-Sun1995 hit the nail on the head: if you charge a merchant through an App Store listing, that transaction has to go through Shopify’s own billing system. Why? Because a Razorpay charge for a Shopify app is essentially "invisible" to Shopify. They can't show it on the merchant’s invoice, they can’t facilitate refunds, and it breaks their billing ecosystem. Shopify wants a consistent, transparent experience for merchants using apps from their store.

Your Dual Billing Strategy: Separating Paths

The solution isn’t to ditch Razorpay entirely, but to implement a clear, server-side separation for your billing paths. This is where the community insights really shine, particularly Taha_Dev’s detailed breakdown in response to a similar issue raised by divyan154.

Path 1: Shopify-Origin Merchants (App Store Installs)

If a merchant installs your app from the Shopify App Store, or even if they start with a free/trial account on your site and then connect their Shopify store, any charges for your app *must* go through Shopify’s billing system. This means:

  1. Shopify App Pricing: This is Shopify’s hosted plan page within the admin. It’s often the simplest way to set up recurring app charges.
  2. Shopify Billing API: If you need a custom plan UI or more complex billing models, you’ll use this API to create charges that merchants approve directly in their Shopify admin.

Crucially: A Shopify-origin merchant should never encounter your Razorpay checkout, pricing page, or any upgrade button that leads off-platform for their app subscription. Reviewers are thorough; they’ll click around your dashboard to ensure this separation is enforced.

Path 2: Standalone Web App Customers (Razorpay is King)

For customers who signed up directly on your website and are paying you via Razorpay *before* ever connecting a Shopify store, great news: Razorpay stays exactly where it is! As Taha_Dev explained, owning a Shopify store doesn’t automatically force them onto Shopify Billing if their paid relationship with you started elsewhere. Just make sure you tie this to a genuine, pre-existing paid subscription and avoid double-billing.

Making the Switch: Practical Steps for a Smooth Review

Divyan154 shared their experience of getting suspended because Razorpay was reachable during the OAuth flow, which perfectly illustrates the need for a robust solution. Here’s how you can implement these dual billing paths and get your app approved:

  1. Determine Billing Rail Early: On your server, immediately after a shop is connected, decide which billing path that account will follow. Store this decision and stick to it. Taha_Dev provided a fantastic example for this logic:
    // 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();
    }
  2. Enforce Billing Path Redirects: For Shopify-rail accounts, any links to pricing, upgrades, or billing settings should redirect to Shopify’s hosted plan page (e.g., https://admin.shopify.com/store/{store_handle}/charges/{app_handle}/pricing_plans) or trigger the Shopify Billing API. For Razorpay-rail accounts, they can continue using your Razorpay-integrated pages.
  3. Review Your OAuth Flow: Ensure your install path is fully compliant. Never ask for a myshopify.com domain during installation, OAuth should run immediately, and after approving scopes, the merchant should land directly in your app UI.
  4. Prepare for Resubmission: As Taha_Dev wisely advises, don't treat review as an iterative QA pass. Fix everything in one go.
    • Detailed Notes: At the top of your testing instructions, clearly explain what you’ve changed. State that Razorpay is *only* for customers who paid you before connecting Shopify, and it’s unreachable for Shopify-origin installs.
    • Screencast: Provide a screencast showing the full install-to-upgrade flow for a Shopify-origin merchant (install from App Store → OAuth → app UI → upgrade through Shopify’s billing → uninstall and reinstall). If you keep the existing-customer path, show it separately with working test credentials.
    • Avoid Misleading Checkboxes: Do NOT tick “I have approval to charge merchants outside of the Shopify Billing API” unless you’ve explicitly received that rare exemption from Shopify.

It can feel like a lot to juggle, but by clearly separating your app’s billing for Shopify-origin merchants from your standalone web app’s billing, you’ll not only meet Shopify’s requirements but also provide a much smoother, more transparent experience for all your users. The key is that distinct path for distinct origins, ensuring that when a merchant comes through the Shopify ecosystem, their app charges stay within it. Good luck with your next submission!

Share:

Start with the tools

Explore migration tools

See options, compare methods, and pick the path that fits your store.

Explore migration tools