Skip to main content
Question

Fetching from API as webhook fallback in transfer case

  • September 2, 2025
  • 8 replies
  • 86 views

Forum|alt.badge.img+2

I want to fetch state from API in addition to webhook handling, for improved resilience.

My subscriptions are credits based, when there’s initial/renewal event, I assign a number of credits to the user.

Not sure how to proceed with the transfer webhook event:

The user installs the app on device A: they get id 1. The user subscribes. My backend has id 1 → 10 credits.

The user installs the app on device B: they get id 2.

Let’s say that the backend for some reason doesn’t receive or process the transfer webhook, so it’s not aware that id 1 → id 2

Now device B, with its id 2, triggers a refresh from RevenueCat api: I get that id 2 has a subscription.

Since I don’t have the old id, all I can do here is to create a new record for id 2 with 10 credits, as if it was a new user. Which is incorrect, because it’s effectively duplicating the credits for the user, who can now use 10 credits on device A and 10 credits on device B.

How can I associate the subscription data to the old id? 

Also, is the whole reasoning correct, or am I missing something else?

Thanks!

Noting that my webhook transfer handler basically removes the old user and creates a new one with the same data and new id (thereby a “transfer”). Not 100% sure that this behavior is correct / expected, but at least it’s straight forward technically.

Using subscriptions endpoint:

"https://api.revenuecat.com/v2/projects/$projectId/customers/$userIdStr/subscriptions"

 

This post has been closed for comments

8 replies

Forum|alt.badge.img+2
  • Author
  • Active Member
  • September 3, 2025

I added this check now to detect the transfer:
 

if (subscription.originalUserId != userId) {    userDao.transfer(subscription.originalUserId, userId)}

// update transferred subscription with fetched data..

Probably fine?


jeffrey_bunn
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • September 9, 2025

Hi ​@user-0a9831! I just wanted to mention our Virtual Currency feature, as it handles the unlocking, transferring, revocation, etc, of digital assets within your app. Do you think this might be simpler than the webhook logic you’re working on? 


Forum|alt.badge.img+2
  • Author
  • Active Member
  • September 12, 2025

Hi ​@jeffrey_bunn 

thanks, I’ve seen it mentioned but as far I understand it requires me to call RevenueCat with each billable request, right? don’t want to add more latency, ideally..


hussain
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • September 18, 2025

Hi ​@user-0a9831,

Thanks for following up. Our Virtual Currency feature is designed to handle unlocking/spend/transfer/revocation of consumables directly within RevenueCat. But you would need to make a call to RevenueCat for each balance change. If your concern is latency and you prefer to keep credits managed directly in your backend, then sticking with the transfer detection logic you’ve built is a solid approach.

For your original question, I’d recommend to treat any new app_user_id that comes from a transfer as an alias of the original user profile where you store balances. This way, instead of creating a separate record (which could double credits), you’re linking multiple IDs back to a single canonical user profile in your system. This would mean:

  • If you detect a transfer via webhook or the API, you can safely add the new ID as an alias to the existing profile.

  • All balances, credits, and state remain tied to the original profile.

  • Any future calls that come in with either the old or the new ID will resolve to the same underlying user and balance.

Hope this helps, let me know if you have any other questions. I’m happy to help.

Best,

Hussain


Forum|alt.badge.img+2
  • Author
  • Active Member
  • September 23, 2025

Hi ​@hussain 

thanks!

I realized that this alias system also helps with account deletion:

  1. User subscribes and consumes some credits
  2. User deletes account
  3. User re-installs app (gets new uuid)
  4. With my current system, this would re-create the account (with topped up credits).

With the alias, I can trace back to the original uuid to know that it was deleted, to not allow to re-create the account.

Anything I’m missing?


Forum|alt.badge.img+2
  • Author
  • Active Member
  • September 24, 2025

@hussain 

Another issue/question, I noticed that the subscription data via your API can only be fetched using the new id. Right? If yes, at least for you API I always need to use the “alias”.


Forum|alt.badge.img+2
  • Author
  • Active Member
  • September 24, 2025

@hussain 

Sorry, found one more issue while implementing the aliasing logic:

I got a transfer event:

2025-09-24 07:37:27.900 🐱📲 Transfer(transfer=TransferData(id=582FB01D-D902-45C9-BA52-E54DA3454AEA, appId=app28e4230723, eventTimestampMs=1758692247376, environment=SANDBOX, store=PLAY_STORE, transferredFrom=[32187a9d-777d-40bf-9b77-e31d1177c376], transferredTo=[083075e5-32e8-4ef3-b9fc-d4bbdd8c2ade], subscriberAttributes={}))

This makes my server add an alias (as discussed):

ALIAS 083075e5-32e8-4ef3-b9fc-d4bbdd8c2ade → 32187a9d-777d-40bf-9b77-e31d1177c376

But at a later point, I initiate a subscription, and get this:

2025-09-24 08:25:54.543  🐱⭐ Initial(subscription=Subscription(id=1B512DC6-5A47-4972-80CB-DE54C64B1F74, appId=app28e4230723, eventTimestampMs=1758695154286, environment=SANDBOX, store=PLAY_STORE, appUserId=083075e5-32e8-4ef3-b9fc-d4bbdd8c2ade, originalAppUserId=083075e5-32e8-4ef3-b9fc-d4bbdd8c2ade, aliases=[083075e5-32e8-4ef3-b9fc-d4bbdd8c2ade], ...)

 

Shouldn’t the subscription have the id 32187a9d-777d-40bf-9b77-e31d1177c376 as originalAppUserId?

And so the new alias logic breaks the handling of the subscription event, because I map the alias to original id, but I can’t do anything with this original id because RevenueCat seems not to remember it anymore?


kaitlin
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • September 30, 2025

Hey ​@user-0a9831,

On our end, when a transfer occurs, the original ID doesn’t come with as an alias - RevenueCat remembers “32187a9d-777d-40bf-9b77-e31d1177c376” but the customerInfo and purchase history no longer belongs to it, it’s essentially now considered a different user than “083075e5-32e8-4ef3-b9fc-d4bbdd8c2ade”.

As you said, the subscription data can now be only fetched on RevenueCat with the new ID after a transfer occurs. This is the ID that now owns the purchase history and if you checked the customerInfo of the first ID on RevenueCat, it would be empty. 

The suggestion for keeping these IDs together as aliases was just meant to simplify your system, though it will differ from how transfers and aliases occur on RevenueCat. Ideally, if the app user ID “32187a9d-777d-40bf-9b77-e31d1177c376” already exists and you receive a TRANSFER event for that user, you can handle it by adding the ids at the `transferredTo` field to your internal customer profile, so it will now contain both “32187a9d-777d-40bf-9b77-e31d1177c376” and “083075e5-32e8-4ef3-b9fc-d4bbdd8c2ade” and either ID can be used to pull up the relevant history.

Then, when you initiate a subscription, you can use the ID attached to that event to check your system to see if the user has any balance and react accordingly.