Shopify Managed Pricing vs the Billing API: Which to Use

In this guide
Use Shopify App Pricing (the feature formerly called managed pricing) if your plans are recurring, usage-based or a mix; use the Billing API only if you need something it cannot do, such as one-time charges or local-currency prices. The two do not mix inside one app: once plans are defined in the Partner Dashboard, your code must send merchants to Shopify’s hosted plan page instead of creating charges itself. Disclosure: we build Shopify apps under Orbitloft (disclosure); our own app notes inform the “in our experience” parts.
What each one is
According to Shopify’s Shopify App Pricing documentation, you define subscription plans in the Partner Dashboard and Shopify hosts the plan selection page, handles recurring and usage charges, free trials, proration and price changes. The billing overview calls it the default for new public apps when it supports your model, and describes Manual Pricing (your own pricing page plus the Billing API) as the legacy, still-supported path.
| Shopify App Pricing | Manual Pricing (Billing API) | |
|---|---|---|
| Who builds the plan page | Shopify | You |
| Where plans are defined | Partner Dashboard | Your code |
| Recurring charges | Yes (monthly, yearly, or monthly with a yearly discount) | Yes |
| Usage charges | Yes, reported with the App Events API; billed monthly | Yes |
| One-time purchases | No | Yes |
| Plan price currency | USD only; merchants see converted amounts | Local currencies possible |
| Trials | Configured per plan in the Dashboard | Set in your charge request |
| Subscription change notifications | Not by webhook, per Shopify’s page (see below) | Your own handling |
Source for the table: the two Shopify pages linked above, as of October 2026. Confirm there before building; these terms change.
Why they conflict
Shopify’s guidance is explicit: don’t call appSubscriptionCreate or your framework’s billing.request helper to charge merchants once you are on Shopify App Pricing. In our own submissions the symptom was that the “Choose plan” button failed for everyone, test mode or not, with an error saying managed pricing apps cannot use the Billing API to create charges. A reviewer who clicks that button hits it on the first try, and it is the classic requirement 1.2.2 rejection (“billing implemented correctly”). See Why Shopify Rejects Apps for the others.
Note there are two halves to the fix, and we initially did only one:
- The action. The plan button redirects to the hosted page instead of creating a charge.
- The loader. Any Billing API status check that renders the Plans page also fails. In our case the check returned a 403 and the page showed “Application Error” before any button appeared. We replaced it with a read of the installed app’s active subscriptions through the Admin GraphQL API, wrapped in a try/catch so a failed lookup shows “no active plan” instead of crashing. Shopify’s page itself points to the Partner API for status, so treat the in-app GraphQL read as our workaround, not a documented recommendation.
If you use usage billing through the old API (for example overage charges), that call fails too. Move metering to the App Events API, or make the call a logged no-op.
The hosted plan page redirect
The page follows this pattern, from Shopify’s documentation:
https://admin.shopify.com/store/<store_handle>/charges/<app_handle>/pricing_plans
Because that URL is outside your app’s iframe, redirect the top window. In the Remix-based app library we use, the redirect helper from the authenticate call accepts a target: "_top" option. Build the store handle from the session’s shop domain rather than hard-coding it.
The suffixed handle trap
Shopify’s page doesn’t say where to find <app_handle>. This cost us a repeat rejection. We first assumed it was the app’s lowercase listing name, then the subdomain our hosting used. Both were wrong. The real handle is Shopify-assigned and often has a numeric suffix because the bare name was already taken when we re-created apps. Examples from our notes: one app was stocksense-20 while another was contentguard-1, and a few were clean.
| Symptom | Likely cause |
|---|---|
| Completely blank page | Handle not recognized |
| “Select a plan” header but a 404 body | Wrong handle, or plans not published yet |
| Plan cards with prices and Select buttons | Correct handle, plans published |
How to find the real one: open the dev store admin, go to Settings, Apps, click the installed app’s row, and read the last path segment of the management URL (.../app_installations/app/<handle>). The embedded app URL shows it as well. Keep it in an environment variable and default to the verified value.
Two more gotchas. A store handle can be suffixed too, and a wrong store handle in a manual test URL gives a generic “problem loading” screen that looks like an app bug. And a reviewer’s “404 on plan selection” can be a timing artifact: in one case it came from testing before our handle fix had deployed.
Single plan picker, not two
For a Shopify App Pricing app, the hosted page is the source of truth for selection and trial display. Our first Plans page had per-plan buttons that each redirected to the hosted picker, so merchants chose twice, and the in-app cards drifted from the real plans. We changed to read-only plan cards plus one “Choose a plan” button. That also matches requirement 1.2.3, which says merchants must be able to change plans without contacting support or reinstalling.
Testing and notifications
Shopify’s page says that when the app and the store belong to the same Partner organization, every plan can be tested at no charge on a development store. Across organizations only free plans, or plans the Partner marks free to test, are available. It also says subscription changes are not delivered by webhook for Shopify App Pricing; instead you query the Partner API for the active subscription and use the plan handle and shop parameters on the redirect back to your app. It adds that apps enrolled before April 2026 could use the subscription webhook until April 28, 2026. Read the current page before designing sync, since this is the sort of detail that changes.
Migration and rollout checklist
If you are switching an existing app, work through this in order. Shopify’s page says apps with Billing API plans that are incompatible with Shopify App Pricing must remove them before switching, and that charges created before you opt in keep processing.
| Step | What to do | Why |
|---|---|---|
| 1 | Define plans in the Dashboard: Distribution, Manage listing, Pricing content, Settings, choose Shopify App Pricing | Plans must exist before the hosted page can render them |
| 2 | Match plan names, prices and trial days to what the app UI says | Mismatches fail pricing accuracy (4.2.1) |
| 3 | Replace the plan button action with a top-level redirect to the hosted page | Removes the Billing API call |
| 4 | Replace the Plans loader’s status check | Avoids the 403 and Application Error |
| 5 | Neutralize old overage or usage-record calls | They are rejected for these apps in our testing |
| 6 | Verify the handle from the installed app’s management URL | Avoids blank and 404 pages |
| 7 | Test as an unsubscribed merchant on a dev store, then select a plan | This is the reviewer’s path |
Keep the handle in an environment variable with a verified default, so a re-created app does not silently break the redirect.
Which should you pick?
- Recurring or usage-based plans in USD, new public app: Shopify App Pricing. Less code and one fewer review surface.
- One-time purchase, or prices in local currency: Manual Pricing with the Billing API.
- Existing app on the Billing API: you may stay; Shopify says existing integrations keep running. Switching requires removing incompatible Billing API plans first.
- Not sure which your app is: open Partner Dashboard, Distribution, Manage listing, Pricing content. If “Shopify App Pricing” is selected, do not call the Billing API. If the hosted
/charges/<handle>/pricing_planspage renders plan cards, that is another reliable sign. We learned that one of our apps was misclassified for days.
Before submitting, walk the whole path as a reviewer would. For listing-side pricing display rules, see the listing checklist, and for review timing see what to expect. If you are choosing between building subscription features yourself or buying them, Shopify subscription apps compared covers the merchant side.
Mistakes to avoid
- Deriving the handle from your hosting subdomain. It rarely matches the Shopify-assigned handle.
- Fixing the button but leaving a Billing API status check in the Plans loader.
- Leaving test-charge defaults on in production for a Billing API app, so real merchants are never billed. Set the flag explicitly at launch and verify with one real plan approval.
- Assuming every app in a portfolio uses the same model. Pricing method is a per-app Dashboard setting, and in our portfolio it was genuinely mixed; two apps were misclassified until we checked each one.
- Describing a plan in the listing that the hosted page does not show.
Frequently asked questions
Can an app use both Shopify App Pricing and the Billing API?
Not for creating new recurring charges. Shopify's documentation says that after you opt in to Shopify App Pricing you cannot create new recurring charges through the Billing API, and existing charges keep processing. In our own testing the Billing API call returned a managed-pricing error for both test and live charges.
When do I still need the Billing API?
For one-time purchases, which Shopify App Pricing does not support, for pricing models it cannot express, and for pricing in a local currency, since plan prices there are set in USD. Existing Billing API integrations can keep running.
Where do I find my app handle for the plan page URL?
Shopify's page shows the pattern but does not say where to find the handle. In our experience the reliable source was the installed app's management URL in the store admin (settings, apps, click the app row), because the handle is often suffixed and differs from your hosting subdomain.
Why does the hosted plan page show a 404 or blank page?
In our experience a blank page meant a wrong handle, and a 404 body usually meant the handle was wrong or the listing's plans were not yet published. Check the handle first.
Is Shopify App Pricing the default for new apps?
Shopify's docs describe it as the default way to charge merchants when it supports your pricing model, and Manual Pricing with the Billing API as the legacy, still-supported option.
Keep planning
- How to Choose a Shopify Agency Without Getting Burned
A decision guide to hiring a Shopify agency: scope first, fixed vs hourly, questions to ask, red flags, and why every agency list (including ours) is biased.
Updated Oct 2026 - Shopify App Store Listing Checklist: Assets, Copy, and Pricing
Every field in a Shopify App Store listing with its limits: icon, 1600x900 images, copy lengths, pricing rules, locked editor and visibility, as of October 2026.
Updated Oct 2026 - Why Shopify Rejects Apps: The Review Failures That Cost Weeks
The recurring reasons Shopify App Store reviews fail (billing gates, dropped query strings, mock data, blank iframes), mapped to requirement IDs and fixes.
Updated Oct 2026


