I’m trying to understand more about the app billing cycles. What would happen in the following situation?
A merchant installs my app, accepts the app subscription plan of $10/month without free trial, then, the same day he changes his subscription to a cheaper plan of $5/month.
In this case, when the next app billing cycle comes, will he be charged only the $5? Or the $10 too, considering that he accepted the $10 plan first?
Thank you!
Hey @Pridentt
When a merchant downgrades to a cheaper plan, Shopify automatically prorates the charges using a specific formula.
For example, If a merchant begins a 30-day billing cycle on a $20.00 plan, and then downgrades to a $10.00 plan on day 15, the proration calculation works like this:
($20.00 - $10.00) * (15/30) = $5.00
This means the merchant receives a $5.00 credit for the unused portion of their higher-priced plan. The formula takes into account both the price difference between plans ($10) and the time remaining in the billing cycle (15 days out of 30), ensuring merchants only pay for what they actually use.
You can find the complete details about how subscription proration works in the documentation: About subscription billing
1 Like
Hello, what would happen if we switch from a paid plan to a free plan? Shopify says the paid plan is still effective until the next billing cycle but the API does not reflect that. In my case (with test charges) the free plan is active immediately and the paid plan is cancelled with currentPeriodEnd = null. How do I, a developer, understand that the paid plan is still active until the next billing cycle if the currentPeriodEnd is null?
This is a limitation with test charges. Currently, when you create a test charge, since it isn’t creating a live billing record, any changes will appear effective immediately.
For live charges, the proration behavior mentioned above will apply. You can use the appSubscriptionReplacementBehaviour to determine if the downgrade should apply immediately (would result in a credit to the merchant for unused time) or apply at the end of the cycle, which would mean the start of the next billing cycle is when they would no longer be charged.
Does this hold true for managed pricing as well? With managed pricing I cannot use the BILLING API so i can’t use appSubscriptionReplacementBehaviour since I am not actually creating the subscription myself.
Thanks for clarifying you’re looking at managed pricing. Managed billing is deferred until the next billing cycle Managed App Pricing
The discrepancy you are seeing comes from how plan changes are made. Since it’s only possible for a merchant to have a single subscription, when they change plans, the old subscription is cancelled immediately and the new one begins.
This is separate from the billing cycle. With managed pricing, since billing is deferred when switching to a free plan, downgrading the functionality should happen at the end of the billing cycle as well.
What you are saying is that the data I receive from shopify’s currentAppInstallation inside the field activeSubscriptions (example below)
{
"nodes": [
{
"id": "gid://shopify/AppSubscription/34934653207",
"currentPeriodEnd": "2025-06-21T09:52:18Z",
"createdAt": "2025-05-22T09:52:15Z",
"name": "Free",
"test": true,
"status": "ACTIVE",
"lineItems": [
{
"id": "gid://shopify/AppSubscriptionLineItem/34934653207?v=1&index=0",
"plan": {
"pricingDetails": {
"__typename": "AppRecurringPricing",
"interval": "EVERY_30_DAYS",
"planHandle": "free",
"price": {
"amount": "0.0",
"currencyCode": "USD"
}
}
}
}
]
},
{
"id": "gid://shopify/AppSubscription/34934587671",
"currentPeriodEnd": null,
"createdAt": "2025-05-22T09:41:46Z",
"name": "Premium",
"test": true,
"status": "CANCELLED",
"lineItems": [
{
"id": "gid://shopify/AppSubscriptionLineItem/34934587671?v=1&index=0",
"plan": {
"pricingDetails": {
"__typename": "AppRecurringPricing",
"interval": "EVERY_30_DAYS",
"planHandle": "premium",
"price": {
"amount": "8.99",
"currencyCode": "USD"
}
}
}
}
]
}
]
}
The cancelled plan will result “cancelled” after the billing cycle? If it results “cancelled” as soon as the user switches to the free plan, how does a developer know that the previous plan is still effective? Note that I cannot use the “createdAt” and “interval” fields to calculate the end date since the “createdAt” field might be outdated if the plan was effective for more than one billing cycles.
Thank you for sharing that. You are right, this is confusing. Test charges have always been a bit confusing to deal with as I mentioned before. I’ll do some more tests here and check in with your billing team to get more clarity for you.