Skip to main content
Question

Can customer subscribe to the same subscription if they are already subscribed (opted-out but not expired yet)?

  • March 24, 2026
  • 5 replies
  • 98 views

Forum|alt.badge.img+3

Hello everyone,

I have a monthly subscription for my Flutter app. Just a single subscription plan.

I faced an issue with at least two customers have an issue with their premium subscription because I am relying on the webhook for their subscription status.

There is a pattern here:
1. Subscribe
2. Opt-out
3. Force resubscribe (?)
4. Subscription expired

From the images below, You can see that the customers manage to subscribe to the same subscription before it expired. I do 

Both of the customers are from Italy and using Android if that matter. Hope to hear any explanation on this. Thanks!

 

 

 

5 replies

guilherme
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • March 26, 2026

Thanks for the detailed write-up and screenshots!

So, when a customer cancels (opts out of renewal), they don't lose access immediately, they keep their subscription until the end of the paid period and if they resubscribe before that period ends, Google Play allows it and backdates the new subscription to the original renewal date.

That's seems to be why you see a new subscription start and the old one expire at almost the same minute, where Google is aligning the billing cycle.

For this flow, RevenueCat sends specific webhook events:

  • CANCELLATION: the customer opted out of renewal, but still has access
  • UNCANCELLATION: the customer re-enabled auto-renew before expiration (they never lost access)
  • EXPIRATION: access is actually revoked
  • RENEWAL: a new billing cycle started. Note that Google Play may classify a resubscription as a RENEWAL rather than an INITIAL_PURCHASE

If your backend is treating CANCELLATION as "revoke premium," that's likely where the sync issue is coming from. You'd want to keep access active on cancellation and only revoke on EXPIRATION. More here: https://www.revenuecat.com/docs/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons

Some extra context on this:

Let me know if you have any questions! Feel free to share the affected App User Ids too, to try and investigate/confirm the Events on the Customer Profile.

Best,


Forum|alt.badge.img+3
  • Author
  • New Member
  • March 27, 2026

Thank you ​@guilherme for the reply.

I’ve looked at the webhook events and there is no `UNCANCELLATION` event triggered. Also, I only revoke premium access on `EXPIRATION`.

If you look at the second image I shared, The subscription started on `2026-03-07` but user manages to resubscribe again on `2026-03-23` and the expiration happened shortly after that. The monthly subscription cycle was not completed yet.

Where can I share the App User Ids? Is sharing here safe? Also do you need the project ID?

Thanks


Forum|alt.badge.img+3
  • Author
  • New Member
  • March 31, 2026

Hello ​@guilherme , could you share where can I share the App User Ids with the RC team?

Thank you


guilherme
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • April 1, 2026

Apologies for the delay here!

Feel free to do it here or via our Support Form - make sure to mention this ongoing thread and also mention me too there, so it loops the right folks internally.


guilherme
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • April 9, 2026

Hey all, just wanted to follow up here with an update since we continued this investigation internally.

After digging into the actual events and purchase receipts, it turns out this is a specific Google Play edge case where a user re-subscribes via the in-app paywall (not the Play Store settings) while their cancelled subscription is still active. Google treats that as a brand new purchase, so a new token gets issued and the old one expires almost immediately. That's why you see an EXPIRATION and INITIAL_PURCHASE land within milliseconds of each other, with no UNCANCELLATION in between.

We are working on a fix that would handle this more gracefully and emit a single UNCANCELLATION event for this flow. In the meantime, the safest approach is to call GET /v1/subscribers/{app_user_id} before revoking access on any EXPIRATION, and only revoke if there's no active subscription on the response.

Thanks for your patience on this! Let us know if you have any follow-up questions.