I’m trying to implement a gift card redemption flow in my ReactNative app. I’m testing in sandbox / staging right now. Currently, once the user inputs a code, it fires of a request to my backend, which does the call to the Grant Entitlements REST API. My backend then returns a success state, and then my frontend rechecks getCustomerInfo, but it’s not working as expected.
TL;DR:
- How should I be checking for customerInfo in my ReactNative app after I grant an entitlement via the REST API? It doesn’t seem to be refreshing correctly?
- It seems to be the case that the user’s Promo entitlement in customerInfo can’t be updated with subsequent successful calls to grantEntitlement, which means that the same user can’t redeem multiple subsequent promotions. Is this just a sandbox / staging thing, a short duration thing (I have it set for 10 min intervals for testing), or is this a production limitation?
FULL CONTEXT
// NOTE: I had to string together multiple examples, so ignore the timestamps
In my app, I make these calls once a user has submitted their giftcode:
// Call the grantEntitlement API
const response = await grantEntitlement(giftCardCode);
// Refresh RevenueCat data
const customerInfo = await Purchases.getCustomerInfo();
console.log('customerInfo', customerInfo);
My grantEntitlement API returns successfully. In fact, here’s a print out of my logs from the backend function, which shows a successful response from the RevCat REST API:
grantResult.subscriber.entitlements.premium {
expires_date: '2024-07-15T05:43:58Z',
grace_period_expires_date: null,
product_identifier: 'rc_promo_premium_custom',
purchase_date: '2024-07-15T05:33:59Z'
}
But when I call getCustomerInfo right after the API returns, I get the following:
{ allPurchasedProductIdentifiers: d],
originalApplicationVersion: null,
activeSubscriptions: a],
allExpirationDatesMillis: {},
requestDateMillis: 1721023380000,
originalPurchaseDateMillis: null,
latestExpirationDate: null,
originalAppUserId: '$RCAnonymousID:706f2861bcbf4a0a8e84ed77c7dc7ca4',
allExpirationDates: {},
managementURL: null,
allPurchaseDates: {},
nonSubscriptionTransactions: r],
originalPurchaseDate: null,
firstSeen: '2024-07-12T21:08:37Z',
latestExpirationDateMillis: null,
entitlements: { active: {}, verification: 'NOT_REQUESTED', all: {} },
requestDate: '2024-07-15T06:03:00Z',
firstSeenMillis: 1720818517000,
allPurchaseDatesMillis: {} }
so the entitlements.active is empty. But! If I log out, and then log back in, where I call Purchases.login(), I get the following customerInfo (called like this: const {customerInfo, created} = await Purchases.logIn(currentUser.username);)
{ allPurchaseDatesMillis: { rc_promo_premium_custom: 1721023422000 },
originalApplicationVersion: null,
activeSubscriptions: 'rc_promo_premium_custom' ],
entitlements:
{ active:
{ premium:
{ willRenew: false,
ownershipType: 'PURCHASED',
expirationDate: '2024-07-15T06:13:41Z',
latestPurchaseDate: '2024-07-15T06:03:42Z',
verification: 'NOT_REQUESTED',
originalPurchaseDate: '2024-07-15T06:03:42Z',
productIdentifier: 'rc_promo_premium_custom',
isSandbox: false,
latestPurchaseDateMillis: 1721023422000,
billingIssueDetectedAtMillis: null,
periodType: 'NORMAL',
isActive: true,
unsubscribeDetectedAt: null,
productPlanIdentifier: null,
store: 'PROMOTIONAL',
identifier: 'premium',
expirationDateMillis: 1721024021000,
originalPurchaseDateMillis: 1721023422000,
unsubscribeDetectedAtMillis: null,
billingIssueDetectedAt: null } },
all:
{ premium:
{ productIdentifier: 'rc_promo_premium_custom',
originalPurchaseDateMillis: 1721023422000,
willRenew: false,
ownershipType: 'PURCHASED',
latestPurchaseDate: '2024-07-15T06:03:42Z',
billingIssueDetectedAt: null,
unsubscribeDetectedAtMillis: null,
latestPurchaseDateMillis: 1721023422000,
isSandbox: false,
originalPurchaseDate: '2024-07-15T06:03:42Z',
verification: 'NOT_REQUESTED',
store: 'PROMOTIONAL',
periodType: 'NORMAL',
identifier: 'premium',
unsubscribeDetectedAt: null,
isActive: true,
productPlanIdentifier: null,
expirationDateMillis: 1721024021000,
billingIssueDetectedAtMillis: null,
expirationDate: '2024-07-15T06:13:41Z' } },
verification: 'NOT_REQUESTED' },
allPurchasedProductIdentifiers: e 'rc_promo_premium_custom' ],
firstSeen: '2024-07-12T21:08:37Z',
originalAppUserId: '$RCAnonymousID:.... ID ... ',
allExpirationDates: { rc_promo_premium_custom: '2024-07-15T06:13:41Z' },
nonSubscriptionTransactions: c],
originalPurchaseDate: null,
firstSeenMillis: 1720818517000,
allExpirationDatesMillis: { rc_promo_premium_custom: 1721024021000 },
originalPurchaseDateMillis: null,
latestExpirationDate: '2024-07-15T06:13:41Z',
requestDateMillis: 1721023578980,
latestExpirationDateMillis: 1721024021000,
requestDate: '2024-07-15T06:06:18Z',
managementURL: null,
allPurchaseDates: { rc_promo_premium_custom: '2024-07-15T06:03:42Z' } }
So I’m able to get a correct entitlement that’s active, just not when calling getCustomerInfo immediately after I grant the entitlement.
What’s the right way to getCustomerInfo after I call grant entitlement? The rest of my app kind of relies on CustomerInfo to present premium status in the right way, and if this isn’t it, I’d like to know what to do differently.
---
Also, after my entitlement expires, and I try to redeem another giftcode, the customerInfo reads:
{"activeSubscriptions": a], "allExpirationDates": {"rc_promo_premium_custom": "2024-07-15T05:46:52Z"}, "allExpirationDatesMillis": {"rc_promo_premium_custom": 1721022412000}, "allPurchaseDates": {"rc_promo_premium_custom": "2024-07-15T05:36:52Z"}, "allPurchaseDatesMillis": {"rc_promo_premium_custom": 1721021812000}, "allPurchasedProductIdentifiers": ""rc_promo_premium_custom"], "entitlements": {"active": {}, "all": {"premium": {Object]}, "verification": "NOT_REQUESTED"}, "firstSeen": "2024-07-10T21:38:45Z", "firstSeenMillis": 1720647525000, "latestExpirationDate": "2024-07-15T05:46:52Z", "latestExpirationDateMillis": 1721022412000, "managementURL": null, "nonSubscriptionTransactions": l], "originalAppUserId": "$RCAnonymousID:...ID....", "originalApplicationVersion": null, "originalPurchaseDate": null, "originalPurchaseDateMillis": null, "requestDate": "2024-07-15T05:47:34Z", "requestDateMillis": 1721022454000}
The previous redeemed giftcode is present, but there’s no indication of the new call to grantEntitlement, and the activeSubscriptions is empty.
This seems to persist for a long time, where subsequent calls to grantEntitlement doesn’t seem to refresh the active state on the user’s entitlement. Also, when I log out and call Purchases.logIn, active entitlements stays empty and the old promo entitlement is still shown (this is called a minute after trying to redeem a new giftcode).
{ allPurchaseDates: { rc_promo_premium_custom: '2024-07-15T06:03:42Z' },
managementURL: null,
allPurchaseDatesMillis: { rc_promo_premium_custom: 1721023422000 },
requestDate: '2024-07-15T06:29:45Z',
activeSubscriptions: T],
originalApplicationVersion: null,
originalAppUserId: '$RCAnonymousID:...ID...',
allExpirationDates: { rc_promo_premium_custom: '2024-07-15T06:13:41Z' },
originalPurchaseDate: null,
nonSubscriptionTransactions: u],
originalPurchaseDateMillis: null,
allExpirationDatesMillis: { rc_promo_premium_custom: 1721024021000 },
requestDateMillis: 1721024985760,
latestExpirationDate: '2024-07-15T06:13:41Z',
latestExpirationDateMillis: 1721024021000,
firstSeen: '2024-07-12T21:08:37Z',
firstSeenMillis: 1720818517000,
allPurchasedProductIdentifiers: , 'rc_promo_premium_custom' ],
entitlements:
{ active: {},
verification: 'NOT_REQUESTED',
all:
{ premium:
{ ownershipType: 'PURCHASED',
willRenew: false,
unsubscribeDetectedAtMillis: null,
billingIssueDetectedAt: null,
expirationDate: '2024-07-15T06:13:41Z',
isSandbox: false,
latestPurchaseDateMillis: 1721023422000,
verification: 'NOT_REQUESTED',
originalPurchaseDate: '2024-07-15T06:03:42Z',
latestPurchaseDate: '2024-07-15T06:03:42Z',
store: 'PROMOTIONAL',
identifier: 'premium',
isActive: false,
productPlanIdentifier: null,
periodType: 'NORMAL',
unsubscribeDetectedAt: null,
originalPurchaseDateMillis: 1721023422000,
billingIssueDetectedAtMillis: null,
productIdentifier: 'rc_promo_premium_custom',
expirationDateMillis: 1721024021000 } } } }
Is it the case that, after I make the first call to grant entitlement API, subsequent calls doesn’t actually have an impact on active subscriptions? Or is this just an artifact of staging / sandbox environments.
FWIW, I have my endMS for the granted entitlement set for 10 minutes after I initiate the call, so maybe the duration is just too short?
Thanks so much for your help! I’d love to push this to production soon, but I don’t want to do it in a way where I don’t understand the limitations or the flow of data.