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