How to verify that subscription offer is redeemed successfully for users with active subscription

Hello,


We're implementing subscription offers in our app and all goes fairly well. However, if user has an active subscription (same plan / product ID) while redeeming the offer, we're getting failed transaction from the payment queue, despite system popover states that "You're all set". I'm not aware if it's documented anywhere, but I assume that the failed transaction in this case indicates, that user hasn't been charged. And yet, this is source of confusion — how do we know, if user redeemed the offer successfully or not?


That said, we started observing another inconsistency this week: StoreKit documentation states that we must use transaction's error property "to determine what happened", but in aforementioned scenario it is actually nil. I'd like to consider the absence of error as an indirect evidence, that the transaction was actually successful, and yet I haven't seen any documentation to support this hypothesis.


Is it intended behaviour or a bug in sandbox?


UPDATE: It looks like the

transaction.error
and
transaction.payment.paymentDiscount
are nil on the mac, but present on iPad (for same test account) for existing subscribers, though error message is still vague in the latter case:

Error Domain=SKErrorDomain Code=0 "Cannot connect to iTunes Store" UserInfo={NSLocalizedDescription=Cannot connect to iTunes Store}


UPDATE 2: Submitted a bug regarding this issue.

Replies

Hello! We have the same issue. And it's happening in Production as well.

Actually this happens not only when redeeming subscription offer. You can try purchasing a regular subscription while current is still active. When you're downgrading subsription or cross-grading with dirreferent duration, you will still get 'You're all set' message but an error that transaction failed.


I found this message from Apple staff (read Rich's answer): https://forums.developer.apple.com/thread/112663


I don't know how to avoid this issue and it's very frustrating.

Hi there!


We are also experiencing the same issue where we cannot apply a promotional offer (i.e. 1 free month) on an active subscription in the sandbox environment. We are, however, able to successfully subscribe with no promo offers and also subscribe to a new subscription with a promo offer for one free month.


Is there any update on this? It's extremely challenging to test this in the sandbox environment without knowing if this will be the case in production.


Thanks!

Eann

It occurs to me that an app which offers a auto-renewable subscription knows or can determine at app launch time whether there is an active subscription. With this knowledge, the app should know what subscription items are upgrades, downgrades or crossgrades. The app could choose to offer only upgrade items for the user to purchase by hiding downgrade purchase items. Alternatively, it can offer all possible subscription items and alert the user in the case that a downgrade purchase is attempted, that the transaction attempt will proceed but the billing will take place when the current subscription expires. It's important to note that the app should already know that there is an active subscription so a downgrade purchase attempt when it fails will not result in a loss of service.


The AppStoreConnect document describes the fact that downgrade purchase attempts will go into affect when the current subscription expires. In this case, as there is no transaction processed, the .purchased event is not returned to the updatedTransactions delegate method. This leaves the .failed transaction state. When the .failed state is returned, there is an SKError associated with the failure. To ensure compatibility with older versions of iOS, SKError is returned as 0 - an unspecified error occurred - which gets translated in the string "Cannot connect to the App Store".


As to the question of what is a subscription downgrade, upgrade or crossgrade - this is a question best posed to AppStoreConnect. They can respond authoritatively where I cannot.


As to testing this in the sandbox, the compressed subscription periods can interfere with the process. Testing upgrades doesn't seem be an issue. For downgrades, define an annual subscription item which renews in the sandbox in 1 hour. Then define a one month subscription item as a downgrade item. If a test user purchases the annual subscription first, then before the hour passes, attempts to purchase the 1 month subscription, the user will be presented with the alert - "You're all set ..." and the app will see the .failed transaction state at the updatedTransactions delegate.


As for how to handle the .failure state in the updatedTransactions delegate method, I would use the NSLog method to log this result to the system log. iOS attempts to present the user with information as to the transaction result. The one confusing case occurs with the "interrupted transaction flow", but that is a different topic.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI