Building a Shopify App: Billing API and Plans Guide
Shopify's Billing API looks simple in the docs, then breaks in production. Here's what most developers miss when wiring up plans and subscriptions.
· Deixtra

Building a Shopify App: Billing API, Plans and What Most Developers Miss
A Shopify app works perfectly in development. Every screen loads, every feature runs, the demo store looks great. Then it goes live, a real merchant subscribes to a paid plan, and the billing flow either double-charges them, silently fails to activate the plan, or leaves the app thinking they're still on free tier three days after they paid. This is one of the most common places Shopify apps break, and it rarely shows up until real money is involved.
This article covers how Shopify's Billing API actually behaves once you move past the happy path, how to structure plans properly, and the specific mistakes that catch developers off guard when building for the Shopify App Store.
What Is Shopify's Billing API?
Shopify's Billing API is the mechanism through which apps charge merchants for subscriptions, one-time purchases, or usage-based fees, with Shopify handling the payment processing and taking its revenue share automatically. Instead of integrating a separate payment gateway, the app creates a charge object through Shopify's GraphQL Admin API, redirects the merchant to Shopify's own confirmation page, and then reads back the charge status.
This matters because it removes PCI compliance and payment gateway integration from your workload entirely. The trade-off is that your app now depends on Shopify's approval flow and webhook timing, which behaves differently than a typical Stripe integration.
How Do You Set Up Subscription Plans Correctly?
A subscription plan in Shopify is created using the appSubscriptionCreate mutation, which returns a confirmation URL you redirect the merchant to before the subscription becomes active. The plan only takes effect after the merchant approves it on Shopify's own page, not the moment your code calls the mutation.
Getting plans right means deciding upfront:
Trial days, set once at creation and not something you can silently change later without creating a new charge
Recurring vs one-time pricing, since usage-based and capped pricing use a different mutation shape than flat recurring plans
Test mode, which must be explicitly set on development stores or you risk creating real charges during testing
What Do Most Developers Miss When Building This?
Most developers miss that approving a subscription in Shopify's UI does not automatically mean your app's internal state is updated. The merchant approves the charge on Shopify's page, but your app only knows about it when you either redirect back and check the charge status, or receive the relevant webhook. If either of those steps has a bug, the merchant is billed while your app still thinks they're on the free plan.
Assuming the Redirect Is Guaranteed
Merchants close tabs, lose connection, or get interrupted after approving a charge but before landing back on your app's confirmation page. If your only source of truth is "the merchant returned to this URL," you'll have paying customers your app doesn't recognize as paying. Webhooks like app_subscriptions/update need to be the actual source of truth, with the redirect only used for immediate UI feedback.
Not Handling Plan Downgrades and Cancellations
Upgrading a plan is usually tested thoroughly. Downgrading, or a merchant cancelling and reinstalling the app later, often isn't. Shopify sends app_subscriptions/update for cancellations too, and if that webhook isn't handled with the same care as activation, merchants can keep paid-tier access after cancelling, or lose access incorrectly on reinstall.
Testing Only With Development Stores
Development stores have different billing behaviour than production stores. Free trials, proration, and Shopify's own review process for public app billing plans all behave differently once the app is live and merchants have real payment methods on file. An app that "just works" in a dev store isn't proven until it's tested on a real paid plan in a live store.
Ignoring Currency and Regional Pricing
A flat USD price looks simple until merchants in different regions see it converted awkwardly, or your plan pricing doesn't account for Shopify's regional pricing rules for public apps. This is easy to miss because it never shows up in a single developer's own test store.
How Should You Structure Your Plans?
Start with the fewest plans that clearly separate real usage tiers, since merchants abandon signup flows that ask them to compare too many similar options. A common structure is a free tier with hard usage limits, a mid-tier covering typical stores, and a higher tier for volume. Each tier's limit should map to something the merchant can see and understand, like number of products synced or orders processed, not an abstract feature flag.
What Happens in Production That Doesn't Show Up in Development?
In production, webhook delivery delays, merchant reinstalls, plan changes mid-cycle, and Shopify's own billing review checks all interact in ways a single developer's test store never surfaces. Apps we've built at Deixtra that include billing, subscription tiers and Polaris-based pricing UI are tested specifically around these transition states: what happens when a webhook arrives late, what happens if a merchant uninstalls mid-trial, and what the app shows if Shopify's charge status and the app's internal database briefly disagree.
Key Takeaways
Shopify's Billing API removes payment gateway integration, but shifts the risk to webhook handling and charge status verification
A redirect back to your app is not proof of payment; webhooks are the actual source of truth
Downgrades, cancellations, and reinstalls need the same testing rigor as upgrades
Development store testing doesn't reveal production billing behaviour
Fewer, clearly differentiated plans convert better than many similar tiers
Frequently Asked Questions
Does Shopify take a cut of app subscription revenue?
Yes. Shopify takes a revenue share on paid app charges processed through the Billing API, which varies based on the app's revenue tier under Shopify's current partner terms.
Can I use my own payment gateway instead of Shopify's Billing API?
For apps listed on the Shopify App Store charging for app functionality, Shopify generally requires billing to go through its own Billing API. A separate gateway is only appropriate for charges unrelated to the app itself.
Why did a merchant's plan not activate even though they approved the charge?
This is almost always a webhook handling gap. The approval happens on Shopify's page; your app needs to confirm the resulting charge status through the API or webhook rather than assuming the redirect alone means success.
If you're building or fixing a Shopify app's billing flow and it's not behaving the way the docs suggest it should, send us the problem on WhatsApp. We'll take a look and give you a written scope and fixed quote.
