If you’re building a Shopify App and the billing system is confusing you — you’re not alone.
The documentation is scattered. The settings are buried. And there are a few traps that will silently break your app if you don’t know about them.
This guide walks through the whole thing, step by step.
Quick note before we dive in: If you’re a developer outside the US and you’ve run into payment issues — signing up for Shopify tools, paying for API services, or handling cross-border billing — Pikabao Virtual Card is worth five minutes of your time. It’s a virtual credit card built for exactly this use case. No complicated verification. Works globally. A lot of indie developers are using it. Open your card here: t.me/pikabaobot?start=5e228275-4
First: Understand the Two Pricing Models
Shopify gives every App developer two billing modes.
Managed Pricing
Shopify handles everything. You set up your plans in the Partner Dashboard. When a merchant clicks to subscribe, Shopify shows them a built-in payment page. You write zero billing code.
It’s the default. It’s simple. But you give up full control of the UX.
Manual Pricing
You build the Pricing page yourself. You call the Billing API. You own the entire flow.
More work upfront — but this is what professional apps use, because it lets you design the subscription experience properly.
Most serious Shopify App developers choose Manual Pricing. The rest of this guide assumes that’s what you’re building.
How to Enable Manual Pricing (The Setting Is Well Hidden)
The default is Managed Pricing. Switching requires clicking through five levels of the Partner Dashboard. Here’s the exact path:
Step 1 Go to your Shopify Partner Dashboard. In the left sidebar, click App distribution > All apps. Select your app.
Step 2 In the left sidebar, click Distribution. Find Manage submission and click it. This opens the App Store review page.
Step 3 Click Create to add a Language Listing. If you already have one, it will say Edit instead.
Step 4 Inside the Language Listing editor, click Pricing Details in the left sidebar. Scroll down to the Pricing Details section and click Manage.
Step 5 In the Pricing management page, click the Settings button in the top-right corner. Select Manual pricing. Done.
Critical warning: If you create a Language Listing but skip this step, your Billing API calls will throw errors. The switch to Manual Pricing must happen before you start coding the payment flow.
The Subscription Payment Flow
Your Pricing page is built. The user clicks “Subscribe.” Now what?
Here’s the standard three-step implementation for a Remix project.
Step 1 — Create the Subscribe API Route
Create this file in your routes directory:
routes/api.subscribe.tsx
This route calls the appSubscriptionCreate GraphQL mutation on Shopify’s Admin API:
mutation appSubscriptionCreate(
$name: String!
$lineItems: [AppSubscriptionLineItemInput!]!
$returnUrl: URL!
$test: Boolean
) {
appSubscriptionCreate(
name: $name
lineItems: $lineItems
returnUrl: $returnUrl
test: $test
) {
appSubscription {
id
}
confirmationUrl
userErrors {
field
message
}
}
}
The parameters you need to pass:
name— your plan name (e.g., “Pro Plan”)returnUrl— where Shopify redirects the user after they confirm paymenttest— set totrueif your app is not yet livelineItems— pricing details (amount, currency, interval)
About the test flag: If your app hasn’t been published yet, you must pass test: true. Shopify reviewers will actually go through your subscription flow when they review your submission. If the flow fails, they’ll reject the app and send it back. Test mode shows a banner that reads something like “You will not be charged for this test transaction” — that’s expected behavior.
Step 2 — Call the Subscribe API from Your Frontend
On your Pricing page, wire the subscribe button to this API call:
const response = await fetch('/api/subscribe', {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.success && data.confirmationUrl) {
// Shopify Apps run inside an iframe in Shopify Admin.
// You must use window.top to break out of the iframe.
// Using window.location.href directly will silently fail.
if (window.top) {
window.top.location.href = data.confirmationUrl;
} else {
window.location.href = data.confirmationUrl;
}
} else {
console.error('Subscription failed:', data.message);
}
The window.top part matters. Shopify embeds your app inside an iframe inside Shopify Admin. If you redirect using window.location.href, the redirect happens inside the iframe and the user never lands on the Shopify payment confirmation page. Always use window.top.location.href for external redirects in embedded apps.
Step 3 — Read the Active Subscription on Return
After the user confirms payment, Shopify redirects them to your returnUrl. On that page, query the active subscription to know which plan they’re on:
query {
currentAppInstallation {
activeSubscriptions {
id
name
status
lineItems {
plan {
pricingDetails {
... on AppRecurringPricing {
price {
amount
currencyCode
}
interval
}
}
}
}
}
}
}
Use this data to enable or restrict features by plan tier. Store the subscription state server-side. Do not use client-side checks to gate features — they can be bypassed.
The Cancellation Flow
Shopify requires every app with paid subscriptions to include a clear cancellation option. This is not optional. If reviewers cannot find it, your app will be rejected.
The cancellation flow is simpler than the subscription flow. Two steps.
Step 1 — Create the Cancel API Route
Create this file:
routes/api.cancel-subscribe.tsx
This route does two things in sequence: fetches the active subscription ID, then cancels it.
# First: get the active subscription ID
query {
currentAppInstallation {
activeSubscriptions {
id
name
}
}
}
# Then: cancel it
mutation appSubscriptionCancel($id: ID!) {
appSubscriptionCancel(id: $id) {
appSubscription {
id
status
}
userErrors {
field
message
}
}
}
Step 2 — Call It from the Frontend
const response = await fetch('/api/cancel-subscription', {
method: 'POST'
});
That’s the whole thing. Handle the response, update your UI, and redirect or notify the user as needed.
One More Thing: Cross-Border Payments
This guide covers Shopify’s billing system. But there’s a related problem that a lot of non-US developers run into and nobody talks about clearly.
Many development tools, API services, and Shopify ecosystem products require an international credit card. If you’re based outside the US or EU, getting one that actually works can be a genuine blocker.
Pikabao Virtual Card solves this. It’s a virtual card that works for international subscriptions, developer tooling, and cross-border payments. Setup is fast and the verification process is straightforward.
If you’ve hit a payment wall mid-build, this is the practical fix: t.me/pikabaobot?start=5e228275-4
Summary
Here’s the short version:
Shopify defaults to Managed Pricing — switch to Manual in the Partner Dashboard before you touch the Billing API.
The subscription flow is three steps: create a subscribe route, call it from the frontend with window.top redirect, then read the active subscription on return.
The cancellation flow is two steps: create a cancel route, call it from the frontend.
Get these right and you have a working monetization system.
That’s what turns an app into a product.
If you have questions about the implementation, drop them in the comments. Happy to dig into specifics.
<!– INSERT PIKABAO INVITATION IMAGE WITH LINK HERE –> <!– Link: https://t.me/pikabaobot?start=5e228275-4 –>
