I have an app published on Shopify App Store and one is in the making. Developing Shopify apps for more than an year, I believe they are major short-comings in the Billing API which make it a very tedious process for implementing & testing billing in Shopify Apps. I will list them down below. I really hope something gets done about these:
Consider the scenario:
-
A Shopify App has some basic features available to use for free and some premium features which require a Premium subscription.
-
A user installs the app on 5 JAN 2019 and buys a Premium subscription plan on 10 JAN 2019.
-
The user uses it for a few months on the Premium plan but then decided to switch to the free plan on 20 APR 2019. He cancels his app subscription but still keeping the app installed and using the free features.
-
His last billing must have happened on 10 APR 2019 (10 JAN + 90 days). Since, he has cancelled the subscription he would still be charged for the full month.
-
Since he has paid for the full month in the last billing he is entitled to use our Premium Services until 10 MAY 2019 (10 APR + 30 days)
How do you suggest I can implement this in our app?
Things to consider
(I am using graphQL for these requests)
- Until the user cancels his subscription everything works as expected. For example, if I check userâs activeSubscriptions on 16 APR 2019, it returns me with
"activeSubscriptions": [{
"createdAt": "2019-01-10T00:00:00Z",
"currentPeriodEnd": "2019-05-10T00:00:00Z",
"id": "gid://shopify/AppSubscription/xxxxxx",
"name": "Premium",
"returnUrl": "https://xxxxxxxx.xxx",
"status": "ACTIVE",
"test": false,
"trialDays": 0
}]
It shows one subscription which has status as âACTIVEâ and also currentPeriodEnd as â2019-05-10T00:00:00Zâ .. which works great. I can check that the user has an active plan and also I can show the user that his current cycle ends on 10 MAY. No problems here butâŚ
- If I check his activeSubscriptions after 20 APR 2019, it returns with
"activeSubscriptions": []
It comes as empty thereby making it difficult for me to know the userâs âcurrentPeriodEndâ, since he has already paid for the full month and should be able to use our appâs Premium features until then.
I know the first thought that comes to mind at this point is, âwe should have saved the activeSubscriptionâs id when he created it and then check the âcurrentPeriodEndâ of this subscription using this idâ. Sure letâs do that.
- When we check for allSubscriptions and check for the subscription with the ID we saved at the time of creation this is what we get
"allSubscriptions": {
"edges": [{
"node": {
"createdAt": "2019-01-10T00:00:00Z",
"currentPeriodEnd": null,
"id": "gid://shopify/AppSubscription/xxxxxx",
"name": "Premium",
"returnUrl": "https://xxxxxxxx.xxx",
"status": "CANCELLED",
"test": false,
"trialDays": 0
}
}]
}
Status is correctly âCANCELLEDâ but guess what âcurrentPeriodEndâ is null now!! Making it impossible for our app to decided, should we continue providing Premium services to this customer or not.
I know the next thought that comes to mind âwe should have saved the âcurrentPeriodEndâ in our database when the subscription was createdâ. Sure letâs do that ...
-
For the first month, saving the âcurrentPeriodEndâ in our database works great. I have a definite way of knowing the last date until which I need to provide Premium services, even if the user cancels his subscription. But for the second month, "currentPeriodEnd" gets updated in Shopifyâs system but I have no way of updating it in my database.
âI know what you are thinking - âwebhooksâ ..right?â . Sure, lets do that ⌠-
We subscribed to the topic APP_SUBSCRIPTIONS_UPDATE and then we wait .. and wait .. and wait! To our surprise, this webhook does not get fired when the âcurrentPeriodEndâ changes at the end of a monthly app subscription cycle. No way to update "currentPeriodEnd" in our database.
To make matters worse, the test charge for testing Billing APIs works very differently than the actual charge. The âcurrentPeriodEndâ in a test charge is the same as âcreatedAtâ instead of âcreatedAt + 30 daysâ as in a real charge. I have detailed this issue in a separate thread https://community.shopify.com/c/Shopify-APIs-SDKs/GraphQL-appSubscriptionCreate-mutation-with-quot-test-true-quot/m-p/567960#M37807
@Josh from Shopify has acknowledged that this is an issue and he would be logging a request to make the test charge behave same as a real charge. I donât know the current status of that request.
Now, I donât know if I am missing something very obvious here but if I am, then please suggest a solution to the issues I am having.
It has been very difficult to work with Shopifyâs Billing API considering the fact that it is also compulsory to use Shopify Billing. Not been a pleasant experience as much as with other APIs of Shopify.
Proposed Solutions
I would like to propose a couple of solutions:
- (Best solution in my opinion) Like I said above, "activeSubscriptions" works great when the subscription is active. When the user cancels his subscription, instead of returning empty array, "activeSubscriptions" should return the last subscription with status as âCANCELLEDâ and the âcurrentPeriodEndâ as the correct date until which the user has already paid for. Sample response
"activeSubscriptions": [{
"createdAt": "2019-01-10T00:00:00Z",
"currentPeriodEnd": "2019-05-10T00:00:00Z",
"id": "gid://shopify/AppSubscription/xxxxxx",
"name": "Premium",
"returnUrl": "https://xxxxxxxx.xxx",
"status": "CANCELLED",
"test": false,
"trialDays": 0
}]
This will make it super easy for developers to decide what they want to do after the user cancels his subscription. Some developers who want to stop providing Premium services immediately on cancellation can check for âstatusâ and the ones who want to provide Premium services until the user has paid for, can check for the "currentPeriodEnd" . I understand the naming activeSubscriptions may not be fitting this response but there can be another key name like âcurrentSubscriptionsâ or âlastActiveSubscriptionâ etc.
-
(Workable solution) If the "activeSubscriptions " has to return an empty array after cancellation then please do not make the "currentPeriodEnd" as null for the previous subscriptions. A developer can save the subscription ID in his database at the time of its creation and check for its "currentPeriodEnd" even if the user has cancelled his subscription.
-
(Least effort but not the best one) Please fire webhooks under the topic APP_SUBSCRIPTIONS_UPDATE every time a userâs monthly app cycle renews. In the webhook payload, a renewed "currentPeriodEnd" should be sent so that we can update this date in our database and check against it for a user.
Ideally, all 3 should be implemented giving developers the choice to use the one to their liking but even if any of them can be implemented for now, it would really help developers give a smooth billing experience.
@Josh & other Shopify staff, hope you are looking into this.
I am willing to contribute in any way possible to resolve this issue.
Thanks & regards,
Amardeep Singh
p.s. @Jason @KarlOffenberger @HunkyBill @Jordan @Alex Bringing to your notice as well. Your inputs would be very helpful. Thanks.