Purchases involve two app stores, a receipt validator, your backend and a user who may background the app mid-transaction. It is the one flow where a bug takes real money from real people.
Test the interruptions, not the happy path
- Backgrounding the app between payment and confirmation
- Losing connection after the store charges but before you grant
- A purchase completing while the user is signed out
- The same receipt arriving twice
Validate receipts server-side, always
A client that tells your backend a purchase succeeded is a client that can be told to lie. The receipt goes to the store's API from your server, every time.
Make granting idempotent
Keyed on the transaction id, so a retried confirmation cannot grant twice. This is the single most common source of accidental duplicate rewards.
Keep a sandbox rota
Store sandbox accounts get into strange states and stay there. We keep several, documented, and rotate rather than debugging a poisoned one.