Multi platform tracking in-app subscriptions via server notifications

We are developing a mobile app with in-app purchases. We plan to offer one-time purchases and subscriptions. In order to support multiple platforms (iOS and others) we plan to track subscriptions via server-to-server notifications and update client licenses accordingly.

Now we are struggling to match server notifications to receipts in the database. We have to support iOS14, so we can't use the appAccountToken field.

We have the following questions:

  1. Is original_transaction_id unique

    a) globally (across all app store user accounts) ?

    b) in the context of a user account ?

    c) in the context of a subscription group?

  2. Is original_transaction_id + subscription_group_identifier unique

    a) globally (across all app store user accounts) ?

    b) in the context of an user account ?

  3. Can an original_transaction_id change?

  4. If an original_transaction_id changed, how can I reference the INITIAL_BUY receipt?

Thank you for your help!

You stated - "We are developing a mobile app with in-app purchases. We plan to offer one-time purchases and subscriptions. In order to support multiple platforms (iOS and others) we plan to track subscriptions via server-to-server notifications and update client licenses accordingly."

I refer you to the Apple Developer article "Offering a Subscription Across Multiple Apps". You will implement unified account management on your server, to support the user on multiple platforms. On every login, the app process will check with the server to determine what subscription services to activate for the user. The app process may cache active services locally in to support out of network service use. After login, the app should know which services to offer for In-App Purchase.

Whenever an initial purchase is made, for iOS/macOS save the appStoreReceipt to the user account for use to track renewals. Check out the Apple Developer article "Handling Subscription Billing"

You stated - "Now we are struggling to match server notifications to receipts in the database. We have to support iOS14, so we can't use the appAccountToken field." Response - you are correct to consider using the original_transaction_id. It is documented as being unique. As to your questions

Q1. Is original_transaction_id unique a) globally (across all app store user accounts) ? Yes

b) in the context of a user account ? no - take a look at the documentation on original_transaction_id. Renewal transactions will show the same original_transaction_id.

c) in the context of a subscription group? Not clear what you are asking here.

Q3. Can an original_transaction_id change? Response - I'm told that there are cases where this can happen. When you match original_transaction_id make sure to do so for the same transaction period. For example, if you receive a RENEWAL notice for the period 02/01/22 - 02/28/22 - you can check for an existing user record using the same original_transaction_id. But if for some reason, a change occurred - check accounts which a renewal is expected, validate the appStoreReceipt, then compare the original_transaction_id for the same period 02/01/22 - 02/28/22. I say this having asked developers who have reported that the original_transaction_id changed +1 from the previous period's transaction, to submit a bug report. For a specific period, the original_transaction_id will be the same between the server-to-server notification and for the appStoreReceipt. From this point on, the "new" original_transaction_id" will be used. Please note - for thousands of developers, this never happens.

What this means is that on every renewal, you may want to have the server validate the save appStoreReceipt to extract the information on the "latest_receipt_info" as well as from the "pending_renewal_info" section. One more suggestion, if you aren't aware - always submit the JSON request with the "exclude_old_transactions": true key so that the contents of the "latest_receipt_info" has only the most recent transaction(s) and not the complete transaction history.

rich kubota developer technical support CoreOS/Hardware/MFI

Hello Rich,

thank you for your answer.

For Q1: As you answered Q1.a (original_transaction_id globally unique) with yes, we don't need the rest of Q1 and Q2 answered anymore. We are happy with the answer.

For Q3: I am really surprised that an original_transaction_id can change. You stated that if the original_transaction_id gets incremented, it is a bug not a feature.

The workaround you suggest is that we have to re-validate the original receipt to get the new original_transaction_id if we cannot find the old one in the database. You suggest that we can limit the range by only re-validating the receipts that are in close range to renewal.

What if the server notification is a CANCEL notification and we cannot find a matching original_transaction_id? Should we then re-validate all our receipts in the database? We are expecting millions of subscriptions (at least we hope).

How often can we expect to see an changed original_transaction_id ? If this is a very rare case, I might handle that manually instead of programmatically.

Thank you for your help!

Hello BraXel,

You asked - "What if the server notification is a CANCEL notification and we cannot find a matching original_transaction_id? Should we then re-validate all our receipts in the database? We are expecting millions of subscriptions (at least we hope)."

I've only ever have seen the original_transaction_id change (increment) on a renewal, specifically an upgrade or downgrade renewal event. Having said this, I've not seen such a report in quite a while. That said, save the original_transaction_id along with the purchase_date. When the CANCEL event is received, the original_transaction_id should match to that for a RENEWAL notice with a matching purchase_date. If anyone from the App Store Server team can suggest a better means to manage this, I welcome their comments.

rich kubota developer technical support CoreOS/Hardware/MFI

Multi platform tracking in-app subscriptions via server notifications
 
 
Q