All packsApp Store MachinerySolve
storekit 2 transaction.updates listener missed renewals
Forgetting the updates listener misses renewals, refunds, and offer codes
Transaction.updates delivers renewals, Ask to Buy approvals, cross-device purchases, and offer-code redemptions -- not just the purchase you just made. Skipping it misses all of them.
What goes wrong
A purchase flow that only reads the transaction StoreKit hands back from Product.purchase() correctly handles that one purchase, but misses everything that arrives afterward through a different path: subscription renewals, Ask to Buy parental approvals that complete later, purchases restored on another device, and offer-code redemptions specifically arrive through the Transaction.updates async stream, not the purchase() call's return value. An app without that listener running silently stops learning about any of these events.
Why agents get it wrong
The purchase() call's return value looks like the complete answer to "did the purchase work" -- it returns a transaction, the transaction verifies, the code moves on. Nothing about that call signature hints that a second, separate, long-running listener is required to catch everything that isn't the immediate purchase itself; it's a StoreKit 2 architectural requirement that has to be known in advance, not inferred from any one API's shape.
What App Store Machinery pre-decides
Decision 9 has the app start the Transaction.updates listener in its init, before any UI renders -- explicitly documented as "the #1 StoreKit 2 bug" to forget. Offer-code redemption specifically is called out as arriving through this listener, not the purchase return path, which is exactly why the listener has to already be running before a user could possibly redeem a code from the paywall.
Source: ARCHITECTURE.md decision 9