Copy this into your coding assistant and add your request.
Read https://openiap.dev/docs/events/purchase-updated-listener and https://openiap.dev/llms.txt. Follow the reading instructions, detailed reference, and linked guides relevant to my task before making changes.
Inspect my existing project and reuse its framework and conventions. Ask me for missing product decisions. Implement the requested behavior and run the applicable checks.
Show the working result, the commands and actual test results, and any remaining limitations. Keep your explanation brief.
My request: [describe what customers should be able to do]
Fired when a purchase is successful or when a pending purchase is completed.
Duplicate Transaction Replays on iOS
StoreKit can replay the same unfinished transaction through more than one native path during a single connection session. By default, OpenIAP delivers one purchaseUpdated event per iOS transaction ID to purchase-success listeners, while still keeping distinct transactions separate. This prevents entitlement delivery from running twice for the same purchase.
For diagnostics, register the purchase update listener with dedupeTransactionIOS: false. The flag belongs to the purchase update listener only; purchase error listeners do not receive successful StoreKit transactions. Android ignores this iOS-only option.
Listener Setup
swift
let subscription = OpenIapModule.shared.purchaseUpdatedListener(
{ purchase in
print("Purchase updated: \(purchase.productId)")
},
options: nil
)
Registers a listener for successful purchase events.
Opt In to iOS StoreKit Replays
swift
let subscription = OpenIapModule.shared.purchaseUpdatedListener(
{ purchase in
print("StoreKit replay or first delivery: \(purchase.id)")
},
options: PurchaseUpdatedListenerOptions(
dedupeTransactionIOS: false
)
)
swift
import OpenIap
let subscription = OpenIapModule.shared.purchaseUpdatedListener { purchase in
Task {
print("Purchase updated: \(purchase.productId)")
// Verify and deliver
if await verifyPurchaseOnServer(purchase) {
await deliverProduct(purchase.productId)
try await OpenIapModule.shared.finishTransaction(
purchase: purchase,
isConsumable: false
)
}
}
}
// Cleanup when done
OpenIapModule.shared.removeListener(subscription)
Event Payload
The purchase event delivers a Purchase object containing transaction details.