Shopify Managed Pricing vs the Billing API: Which to Use

Cover graphic for the guide 'Shopify Managed Pricing vs the Billing API: Which to Use' on a purple background
Graphic: Ecom Field Guide
In this guide
  1. What each one is
  2. Why they conflict
  3. The hosted plan page redirect
  4. The suffixed handle trap
  5. Single plan picker, not two
  6. Testing and notifications
  7. Migration and rollout checklist
  8. Which should you pick?
  9. Mistakes to avoid

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 PricingManual Pricing (Billing API)
Who builds the plan pageShopifyYou
Where plans are definedPartner DashboardYour code
Recurring chargesYes (monthly, yearly, or monthly with a yearly discount)Yes
Usage chargesYes, reported with the App Events API; billed monthlyYes
One-time purchasesNoYes
Plan price currencyUSD only; merchants see converted amountsLocal currencies possible
TrialsConfigured per plan in the DashboardSet in your charge request
Subscription change notificationsNot 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:

  1. The action. The plan button redirects to the hosted page instead of creating a charge.
  2. 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.

SymptomLikely cause
Completely blank pageHandle not recognized
“Select a plan” header but a 404 bodyWrong handle, or plans not published yet
Plan cards with prices and Select buttonsCorrect 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.

StepWhat to doWhy
1Define plans in the Dashboard: Distribution, Manage listing, Pricing content, Settings, choose Shopify App PricingPlans must exist before the hosted page can render them
2Match plan names, prices and trial days to what the app UI saysMismatches fail pricing accuracy (4.2.1)
3Replace the plan button action with a top-level redirect to the hosted pageRemoves the Billing API call
4Replace the Plans loader’s status checkAvoids the 403 and Application Error
5Neutralize old overage or usage-record callsThey are rejected for these apps in our testing
6Verify the handle from the installed app’s management URLAvoids blank and 404 pages
7Test as an unsubscribed merchant on a dev store, then select a planThis 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_plans page 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.