Best approaches for handling In-App Purchase server validation

I recently built an iOS application that uses In-App Purchases for buying virtual currency (consumable items). My backend runs on Ruby on Rails and I’m questioning some aspects of my implementation.

Current workflow:

  1. iOS app requests product identifiers from the backend.
  2. App fetches product details via StoreKit using those IDs.
  3. User initiates purchase through StoreKit.
  4. App sends receipt data to backend after the transaction completes.
  5. Backend performs initial receipt validation.
  6. Backend contacts Apple servers to verify the receipt and updates the user balance.
  7. App receives confirmation and shows the updated balance.

Coming from a traditional e-commerce background, this feels different since payment providers typically send webhooks directly to servers. We usually implement queue systems for transaction reliability.

Main concerns:

  1. What’s the recommended approach for receipt validation? How do you handle cases where the client completes payment but server validation fails? Users can’t restore non-consumable purchases in this scenario.

  2. Since users expect instant coin delivery (not “processing” messages), how do you balance immediate response with reliable processing? Are message queues still valuable here?

Any insights would be helpful.

Your workflow’s solid but you’re missing server-side notifications - Apple actually recommends these for production apps. Set up App Store Server Notifications to get real-time updates about subscription changes, refunds, and other transaction events sent directly to your backend. This fixes your client-dependency problem. For reliability, I’d use a dual approach: validate receipts immediately for good UX, but also queue validation jobs as backup. When Apple’s servers are down, store the receipt and retry with exponential backoff. You’ll want transaction deduplication using Apple’s transaction IDs to prevent double-crediting if users spam the purchase button. The big difference from regular e-commerce is Apple handles all payment processing, so you focus on receipt verification and fraud prevention instead of payment gateway integration.

Receipt validation’s always messy, no way around it. We store pending transactions locally and retry validation when the app launches if something went wrong. For instant delivery - show the coins right away but flag them as ‘pending’ until validation finishes, then either confirm or roll back if the receipt’s fake.

Interesting setup! Two things I’m wondering about - what happens if users force-close the app right after paying but before your backend validates? And if Apple’s servers are down during verification, do you retry or just fail the user? Seems like tricky timing to handle.