play-billing-samples icon indicating copy to clipboard operation
play-billing-samples copied to clipboard

Free trial state identification in subscriptionV2 response

Open ShambuGIT opened this issue 2 years ago • 21 comments

Our app using the paymentState for identifying the receipt is in free trial or not. Now we are moving to latest API subscriptionV2(https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2/get). But there is no field to identify that it's free trial. Could someone share me the details.

ShambuGIT avatar Nov 13 '22 02:11 ShambuGIT

Perhaps

lineItems
	SubscriptionPurchaseLineItem
		OfferDetails
			offerId?

matale avatar Nov 21 '22 22:11 matale

@matale it returns freetrial in offerId even after conversion of trial. So not able to trust this.

"offerDetails": { "basePlanId": "p1y", "offerId": "freetrial" }

ShambuGIT avatar Nov 22 '22 09:11 ShambuGIT

Any updates on the above?

ksimantov avatar Mar 12 '23 14:03 ksimantov

Also interested in this. We reverted to using the old API just to get this data.

liquidsnk avatar Apr 19 '23 14:04 liquidsnk

Same why would they remove such a valuable information ?

julienlurois avatar May 15 '23 13:05 julienlurois

Also waiting for any progress here. Would continue using the old API until then as suggested by @liquidsnk

affan10 avatar Jun 02 '23 06:06 affan10

This was already an issue with the V1 api for offers that weren't free trials. It would have been nice to have offer state for a subscription in the subscriptionv2/get endpoint but I guess it is too late for that now.

What we are going to do instead is have all the offer configurations in our DB and implement our own logic to ~determine~ guess the free-trial / other offer state for a subscription after fetching the v2 details. This will be slower and ~probably~ for sure sometimes wrong, and it seems like something that would be better done on Google Play side, but I think it's the only way.

To Google: Please properly document this feature so developers understand what they need to do on their side to know the current state of an offer for a subscription. The current documentation is not sufficient.

Edit: Apple's subscription API takes the other approach, where the offer details are only present in the response for the current active subscription if the offer is currently in effect. It could be argued that the downside there is you need to do more checking to know what offer the subscription was purchased with originally, but in practice this is easier to know than whether an offer is still in effect for a subscription at the moment the details were fetched.

pnico avatar Jun 07 '23 16:06 pnico

Do we have any idea when will the subscriptions v1 GET endpoint completely stop working? I can see that for now it is working and exists for backwards compatibility.

affan10 avatar Jun 15 '23 14:06 affan10

his was already an issue with the V1 api for offers that weren't free trials.

No, V1 had a clear payement state free trial.

julienlurois avatar Jun 15 '23 14:06 julienlurois

Do we have any idea when will the subscriptions v1 endpoint completely stop working?

it's very unclear, but the v2 only has the get. It doesn't have cancel/refund/revoke/defer. So it would be strange to fully remove v1.

julienlurois avatar Jun 15 '23 15:06 julienlurois

@julienlurois My bad, I meant only the GET endpoint for subscriptions v1. Just edited the comment.

affan10 avatar Jun 15 '23 15:06 affan10

any update on this?

vnelson1-godaddy avatar Aug 18 '23 00:08 vnelson1-godaddy

I found this solution on Stackoverflow. This hiding in LineItems[0].OfferDetails.OfferId

Please refer this link

nhanlethanh1198 avatar Aug 28 '23 03:08 nhanlethanh1198

@nhanlethanh1198 - As I mentioned before, we tried to use that but the problem is the offerId with freetrial still present even after the renewal. It may be bug in the playstore and so far it was not fixed. We can't trust this for freetrial.

{"acknowledgementState":"ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED","kind":"androidpublisher#subscriptionPurchaseV2","latestOrderId":"GPA.xxxx-xxxx-xxxx-xxxxx..0","lineItems":[{"autoRenewingPlan":{"autoRenewEnabled":true},"expiryTime":"2024-08-28T03:31:06.117Z","offerDetails":{"basePlanId":"p1y","offerId":"freetrial"},"productId":"xxxxxxxxxx"}],"regionCode":"US","startTime":"2023-08-14T03:32:04.885Z","subscriptionState":"SUBSCRIPTION_STATE_ACTIVE"}

ShambuGIT avatar Aug 28 '23 04:08 ShambuGIT

Haven't tested this yet, but a possible solution might be to query the offers endpoint with the offerId included in SubscriptionPurchaseV2.lineItems and then calculate whether the user is still in a free trial phase based on SubscriptionPurchaseV2.startTime and the duration of each of the offer phases

Esarhaddon avatar Sep 13 '23 20:09 Esarhaddon

his was already an issue with the V1 api for offers that weren't free trials.

No, V1 had a clear payement state free trial.

Yes - this is why I specified that it was an issue in V1 for offers that weren't free trials. For offers that were free trials, it was lovely, we were able to easily know that the free-trial offer was currently in effect 😃 For other offers that were not free trials, it was the same as V2 is now, except now you can't know the current state of any offer type, including free trials. Except if you...

Haven't tested this yet, but a possible solution might be to query the offers endpoint with the offerId included in SubscriptionPurchaseV2.lineItems and then calculate whether the user is still in a free trial phase based on SubscriptionPurchaseV2.startTime and the duration of each of the offer phases

This is what we're doing (well, not from the endpoint, we just hardcode it in the DB and update it when we change it 😛 ). As I said before, it's not ideal but it's all we can do.

pnico avatar Sep 15 '23 00:09 pnico

After conducting in-depth research and testing on this issue, we found the meaning of OfferId. let me explain it with one detailed example.

Given one subscription whose productId is pid.aaa. bbb with 7 days period, the free trial of this subscription is 3 days. One user purchased this subscription on 10/01/2023 for the first time, and the transaction id of this purchase is GPA.1111 , the value of OfferId is not empty and equal to the offer name configured in this subscription, now the user could be in the free trial period until 10/04/2023. After 10/04/2023, the real subscription takes effect and the user could be in the first period of the subscription until 10/11/2023, and the transaction id of this purchase could be GPA.111..0, the value of OfferId is not empty either.

When this user cancels the subscription on 10/10/2023, the whole subscription purchase period is done.

However, this user repurchased the same subscription several days later on 10/15/2023. The transaction id of this new purchase is GPA.2222, and the value of OfferId is empty, since there is no free trial period at this new purchase. The expire time of this purchase is 10/22/2023. After 10/22/2023, the new subscription period takes effect, the transaction id is GPA.2222..0 and the value of OfferId is empty.

We know the free trial does NOT take effect in the second purchase, so the value of OfferId is empty.

Based on the above, both the value of OfferId and transaction id are used to distinguish the free trial period of one subscription. Only when the OfferId is not empty and there is NO .. in the transaction id, the value of free trial is true.

richzw avatar Nov 01 '23 09:11 richzw

This is a clever workaround! However, it highlights that this is a problem in the API, if developers are forced to check for ".." in the transaction ID along with the (non-)existence of another field which is not technically for this purpose.

pnico avatar Jan 11 '24 17:01 pnico

After conducting in-depth research and testing on this issue, we found the meaning of OfferId. let me explain it with one detailed example.

Given one subscription whose productId is pid.aaa. bbb with 7 days period, the free trial of this subscription is 3 days. One user purchased this subscription on 10/01/2023 for the first time, and the transaction id of this purchase is GPA.1111 , the value of OfferId is not empty and equal to the offer name configured in this subscription, now the user could be in the free trial period until 10/04/2023. After 10/04/2023, the real subscription takes effect and the user could be in the first period of the subscription until 10/11/2023, and the transaction id of this purchase could be GPA.111..0, the value of OfferId is not empty either.

When this user cancels the subscription on 10/10/2023, the whole subscription purchase period is done.

However, this user repurchased the same subscription several days later on 10/15/2023. The transaction id of this new purchase is GPA.2222, and the value of OfferId is empty, since there is no free trial period at this new purchase. The expire time of this purchase is 10/22/2023. After 10/22/2023, the new subscription period takes effect, the transaction id is GPA.2222..0 and the value of OfferId is empty.

We know the free trial does NOT take effect in the second purchase, so the value of OfferId is empty.

Based on the above, both the value of OfferId and transaction id are used to distinguish the free trial period of one subscription. Only when the OfferId is not empty and there is NO .. in the transaction id, the value of free trial is true.

how to detect Free trial + followed by intro price ?

feiquan123 avatar Jan 18 '24 08:01 feiquan123

Any news on this? We wanted to update our integration to use the V2 API instead of V1 and we need to know the state of the free trial. The workaround mentioned above might work, but as @pnico said above, it doesn't sound like a really sustainable way to go.

niklasastrom avatar Apr 15 '24 15:04 niklasastrom

I m also facing the same issue upgrade subscriptionv1 to subscriptionv2 but the free trail is not working and payment state is not free trail state

vidhyalakhmi avatar Apr 16 '24 13:04 vidhyalakhmi