Search

How to Monetise a Shopify App in 2026: Shopify App Pricing vs the Billing API

How to Monetise a Shopify App in 2026: Shopify App Pricing vs the Billing API

Our badge app works across the admin, product pages and the storefront (part 5). Now let's charge for it.

Also Read: 5 Vital Marketing Marketing Strategy Strategies for SaaS Companies

Billing changed a lot in 2026. In May 2026, "Managed Pricing" was renamed Shopify App Pricing and became the default for new public apps. The GraphQL Billing API still works, but Shopify now calls it legacy ("Manual Pricing"). Most tutorials online still teach the old way.

Series: Shopify App Development 2026, part 6 of 8

The one rule: use Shopify's billing

If your app is on the Shopify App Store, you must charge merchants through Shopify. Stripe checkouts, PayPal links and "email us for an invoice" all break App Store requirement 1.2.1, and Shopify will reject the app (billing overview). Two related requirements:

  • 1.2.2: handle accept, decline and re-approval flows correctly.
  • 1.2.3: merchants must be able to upgrade or downgrade without contacting support.

In return, charges appear on the merchant's normal Shopify invoice. That means less friction for them and no card handling for you.

Also Read: Programming Guide

(Custom apps can't use Shopify billing at all. You invoice those clients directly.)

Shopify App Pricing or the Billing API?

Decision flow for choosing Shopify App Pricing or the legacy Billing API

 Shopify App Pricing (recommended)Manual Pricing (legacy Billing API)
Recurring plans (monthly or annual)✅✅
Usage-based charges✅ via the App Events API✅ via appUsageRecordCreate
One-time charges❌✅ appPurchaseOneTimeCreate
Hosted pricing page✅ Shopify builds and hosts it❌ you build it
Trials, proration, upgrades and downgrades✅ handled for youYou handle them
Code neededA redirect, plus a subscription checkMutations, return URLs, approval handling

The short answer: use Shopify App Pricing unless you need one-time charges. There's no deprecation date for the Billing API, so existing apps don't have to migrate (Shopify App Pricing docs).

Also Read: Web Development: How to Publish

Option 1: Shopify App Pricing

With App Pricing you define plans in a dashboard and Shopify hosts everything else: the plan selection page, trials, proration, upgrades, downgrades and cancellations.

What it supports (as of September 2026)

  • Fixed plans: monthly or yearly, or monthly with a yearly discount
  • Usage-based pricing: fixed, graduated or volume tiers. Up to 5 usage meters per plan and 6 tiers per meter, billed monthly
  • Hybrid: a recurring base price plus usage
  • Up to 8 public plans (up from 4 in July 2026), and unlimited private plans for specific stores (since September 21, 2026, per the changelog)
  • Free trials per plan. Shopify counts trial days over a 180-day window, so merchants can't uninstall and reinstall to get a fresh trial

Step 1: Create your plans

In the Partner Dashboard, go to App distribution → Manage listing → Pricing content → Settings, then set Pricing method to Shopify App Pricing. Add your plans there.

For TWT Product Badges we'll use:

Also Read: Web Development: Shopify GraphQL Admin

PlanPriceIncludes
Free$0Badges on up to 10 products
Pro$4.99/month, 7-day trialUnlimited badges, custom colours

Once you opt into Shopify App Pricing, you can't create new recurring charges with the Billing API for that app. Choose deliberately.

Step 2: Send merchants to the hosted plan page

Shopify hosts the plan selection page at a predictable URL:

https://admin.shopify.com/store/{store_handle}/charges/{app_handle}/pricing_plans

app_handle is the handle in your shopify.app.toml. Here's a route that sends the merchant there. It type-checks against @shopify/shopify-app-react-router 3.0:

// app/routes/app.plans.tsx
import type { LoaderFunctionArgs } from "react-router";
import { authenticate } from "../shopify.server";

// Sends the merchant to Shopify's hosted plan selection page
// (Shopify App Pricing). `handle` is the handle in shopify.app.toml.
const APP_HANDLE = "twt-product-badges";

export const loader = async ({ request }: LoaderFunctionArgs) => {
  const { session, redirect } = await authenticate.admin(request);
  const storeHandle = session.shop.replace(".myshopify.com", "");

  return redirect(
    `https://admin.shopify.com/store/${storeHandle}/charges/${APP_HANDLE}/pricing_plans`,
    { target: "_top" },
  );
};

target: "_top" matters. The admin page has to navigate the whole browser window, not just your app's iframe. Add an "Upgrade" link to /app/plans in your nav or on a gated feature. After the merchant picks a plan, Shopify redirects back to your app with plan_handle and shop query parameters.

Step 3: Check which plan a shop is on

For Shopify App Pricing, Shopify's docs say to check subscriptions with the Partner API, not the Admin API (activeSubscription):

query ActiveSubscription($appId: ID!, $shopId: ID!) {
  activeSubscription(appId: $appId, shopId: $shopId) {
    billingPeriod
    cancelAtEndOfCycle
    trialEndsAt
    items {
      handle
      price {
        __typename
        ... on FlatRatePrice { amount }
      }
    }
  }
}
  • Endpoint: https://partners.shopify.com/{organization_id}/api/2026-07/graphql.json
  • Header: X-Shopify-Access-Token with a Partner API client token that has the Manage apps permission
  • IDs look like gid://shopify/App/1234 and gid://shopify/Shop/5678
  • Rate limit: 4 requests per second per client, so cache the result (for example in your database, keyed by shop) instead of checking on every page load

A simple approach is to store the plan when Shopify redirects back with plan_handle, then re-check with the Partner API on a schedule or before sensitive actions.

Step 4 (optional): Usage-based billing with App Events

To charge per use (per SMS, per AI generation, per order synced), define a meter with an event handle on your plan, then report usage to the App Events API:

curl -X POST "https://api.shopify.com/app/unstable/events" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {access_token}" \
  -d '{
    "shop_id": "gid://shopify/Shop/12345678",
    "event_handle": "sms_sent",
    "timestamp": "2026-01-27T14:30:00Z",
    "idempotency_key": "sms_12345_1706365800",
    "attributes": { "value": 1 }
  }'
  • event_handle must match a meter you configured.
  • idempotency_key is enforced permanently, so retrying is safe and won't double-bill.
  • The API always returns 202, even when billing validation fails. Check the App Events logs in the Dev Dashboard while you build.
  • Since July 2026 you can send negative values (credits) and fractional values.
  • The docs example uses the unstable version path. Check the setup guide for a stable version before you go live.

Testing App Pricing

On dev stores in the same Partner organisation as your app, you can pick any plan at no charge, and $0 test subscriptions are created. App Store reviewers can also pick plans for free. Don't use the Billing API test flag with App Pricing.

Also Read: Build Your First Shopify App with Shopify CLI (2026) - Web Development

Option 2: Manual Pricing (the legacy Billing API)

Use this if you need one-time purchases (credit packs, setup fees, lifetime deals) or you're maintaining an existing app. The flow:

  1. Your app calls a billing mutation.
  2. Shopify returns a confirmationUrl.
  3. You redirect the merchant there to approve or decline.
  4. Shopify sends them back to your returnUrl.

Creating a subscription with GraphQL

mutation AppSubscriptionCreate(
  $name: String!
  $lineItems: [AppSubscriptionLineItemInput!]!
  $returnUrl: URL!
  $trialDays: Int
) {
  appSubscriptionCreate(
    name: $name
    returnUrl: $returnUrl
    lineItems: $lineItems
    trialDays: $trialDays
  ) {
    userErrors { field message }
    appSubscription { id }
    confirmationUrl
  }
}
{
  "name": "Pro",
  "returnUrl": "https://your-app.example.com/app",
  "trialDays": 7,
  "lineItems": [
    {
      "plan": {
        "appRecurringPricingDetails": {
          "price": { "amount": 4.99, "currencyCode": "USD" }
        }
      }
    }
  ]
}

A usage line item uses appUsagePricingDetails with terms and a cappedAmount. You then report usage with appUsageRecordCreate (appSubscriptionCreate docs).

Or let the React Router library do it

The template's library has billing helpers that wrap the Billing API (they don't apply to App Pricing). Define plans in shopify.server.ts:

import { shopifyApp, BillingInterval } from "@shopify/shopify-app-react-router/server";

export const PRO_PLAN = "Pro";

const shopify = shopifyApp({
  // ...existing config
  billing: {
    [PRO_PLAN]: {
      lineItems: [
        { amount: 4.99, currencyCode: "USD", interval: BillingInterval.Every30Days },
      ],
    },
  },
});

Then require the plan in any loader:

export const loader = async ({ request }: LoaderFunctionArgs) => {
  const { billing } = await authenticate.admin(request);

  await billing.require({
    plans: [PRO_PLAN],
    isTest: process.env.NODE_ENV !== "production",
    onFailure: async () => billing.request({ plan: PRO_PLAN }),
  });

  // Merchant has an active Pro subscription
  return null;
};

Use billing.check() when you only want to know the plan without redirecting (for example, to show an upgrade banner). Full reference: React Router billing API.

The classic rejection: submitting your app with test: true or isTest: true still hard-coded. Merchants then use the app without being charged, and Shopify lists this as a common rejection reason. Tie it to the environment as shown above.

Pricing strategy tips

  • Start simple. A free plan or a trial plus one or two paid plans beats a complicated pricing grid.
  • Put pricing only in the pricing section of your listing, never in screenshots or the app icon (requirement 4.2).
  • Gate features, not the whole app. Merchants who can try the core value install more and uninstall less.
  • Show usage on your app's home page ("7 of 10 free badges used"). It sells the upgrade for you, and Built for Shopify expects useful reporting on the home page anyway.

What you actually keep

Say 500 merchants pay $4.99/month:

  • Gross revenue: $2,495.00/month
  • Revenue share: 0% (you're under $1M in lifetime app revenue)
  • 2.9% processing fee: −$72.36
  • You receive ≈ $2,422.64/month, before your own taxes and hosting

Details are in the revenue share docs. Payouts arrive twice a month through Hyperwallet (part 2).

FAQ

Is Managed Pricing the same as Shopify App Pricing?

Yes. Managed Pricing was renamed Shopify App Pricing on May 12, 2026, and gained usage-based and hybrid pricing through the App Events API.

Also Read: Shopify App Development in 2026: The Complete Roadmap

Is the Shopify Billing API deprecated?

It's labelled legacy but still fully works, and there's no announced shutdown date. It's the only option for one-time charges. Shopify provides a migration guide for moving existing plans to App Pricing.

Can I charge merchants through Stripe instead?

Not for App Store apps. Off-platform billing is banned for public apps. Custom apps (for a single client) can't use Shopify billing, so you invoice those clients directly.

How do free trials work?

You set the trial length per plan. With App Pricing, Shopify tracks trial usage over 180 days, so reinstalling doesn't restart the trial. With the Billing API, you pass trialDays when you create the subscription.

Next up

The app can now make money. Next it needs a real home. In Part 7: How to Deploy a Shopify App to Production we'll choose a host, move from SQLite to Postgres, set environment variables, and ship with shopify app deploy and CI/CD.

← Part 5: Shopify App Extensions Explained

TWT Staff

TWT Staff

Writes about Programming, tech news, discuss programming topics for web developers (and Web designers), and talks about SEO tools and techniques

Your experience on this site will be improved by allowing cookies Cookie Policy