Skip to main content

Why Apple Returns latest_receipt_info Instead of in_app During Purchase Verification

Explains why brainCloud logs "No items were processed in transaction [storeId: itunes]" and how to fix it by refreshing the iOS receipt before calling verifyPurchase.

Written by Jason Liang
Updated today

Applies to: iOS / iTunes purchases using brainCloud's appStore.verifyPurchase API

Symptom: APP_WARNING"No items were processed in transaction [storeId: itunes]"

Overview

When a player completes an in-app purchase on iOS, your game client sends the Apple receipt to brainCloud for verification via appStore.verifyPurchase. brainCloud forwards that receipt to Apple's validation server and processes the response.

In some cases — even though the purchase succeeded on Apple's side — brainCloud logs an APP_WARNING and awards nothing. This article explains why that happens and how to prevent it.

How Receipt Validation Works

  1. Player completes a purchase in the iOS app

  2. Apple generates a receipt and stores it on the device

  3. Your client reads the receipt and sends it to brainCloud

  4. brainCloud forwards the receipt to Apple's validation server

  5. Apple returns a JSON response

  6. brainCloud reads the in_app array to identify purchased items

  7. brainCloud awards items and currencies defined in your product catalog

Step 6 is where things can go wrong. If in_app is empty, brainCloud has nothing to process and logs the warning.

What the Warning Looks Like

You'll find this entry under App > Global > Logs > Recent Errors:

{
  "type": "APP_WARNING",
  "service": "appStore",
  "operation": "VERIFY_PURCHASE",
  "message": "No items were processed in transaction [storeId: itunes]",
  "context": {
    "resultCode": 0,
    "transactionSummary": {
      "transactionDetails": [],
      "unprocessedCount": 0,
      "processedCount": 0
    },
    "rewards": {}
  }
}

Notice that resultCode is 0. From Apple's perspective the purchase succeeded — but brainCloud received an incomplete receipt and could not process it.

Why Is in_app Empty?

Apple's validation response includes two fields that can contain purchase data:

Field

What it contains

in_app

Purchases present in the receipt that was submitted

latest_receipt_info

All recent purchases tied to the Apple ID, fetched fresh from Apple's servers

brainCloud reads in_app. When in_app is empty but latest_receipt_info contains the purchase, the submitted receipt is stale — it was generated before the purchase took place.

Common Causes

1. Stale or cached receipt

The most frequent cause. The client sent a receipt that predates the purchase. Apple's in_app array only includes transactions that occurred after the receipt was created.

How to spot it: Compare receipt_creation_date to purchase_date from latest_receipt_info. If the receipt was created before the purchase, it's stale.

"receipt_creation_date": "2026-04-04 21:49:24 Etc/GMT"  ← receipt created Apr 4
"purchase_date":         "2026-04-14 19:49:15 Etc/GMT"  ← purchase made Apr 14

A 10-day-old receipt cannot contain a purchase made today.

2. Receipt read before StoreKit finishes processing

After SKPaymentQueue delivers the transaction, the app must wait for StoreKit to fully process it, then fetch a fresh receipt before calling brainCloud. Reading the receipt too early can result in an empty in_app array.

3. Receipt already validated or consumed

Apple may remove entries from in_app after repeated validations or after acknowledgement. The transaction then appears only in latest_receipt_info as a historical record.

Does latest_receipt_info Belong to the Correct Player?

latest_receipt_info reflects purchases made by the Apple ID that signed the receipt — not necessarily the brainCloud player who submitted the request. You cannot confirm a match from receipt data alone.

To verify identity:

  • Look up the player by profile ID in User > User Browser

  • Confirm they have an iTunes identity linked to their brainCloud account

  • Cross-reference the transaction_id in App > Global > Marketplace > Transactions

If transaction_id equals original_transaction_id, it's a first-time purchase. If they differ, it's a restored purchase.

Impact on POST Hook Scripts

If you have a POST API hook on appStore.VERIFY_PURCHASE, when this warning occurs:

  • transactionSummary.transactionDetails will be an empty array []

  • rewards will be an empty object {}

  • resultCode will still be 0

Guard against this in your hook script to avoid null reference errors:

var transactionDetails = msg.transactionSummary.transactionDetails;
if (transactionDetails && transactionDetails.length > 0) {
    // process items
} else {
    // nothing was processed — handle gracefully
}

How to Fix It

The fix is entirely on the client side: always send a fresh receipt after a purchase completes.

Recommended iOS client flow

  1. SKPaymentQueue delivers the transaction (transactionState == .purchased)

  2. Call SKReceiptRefreshRequest to fetch a fresh receipt from Apple

  3. Wait for the refresh callback to complete

  4. Read the receipt from Bundle.main.appStoreReceiptURL

  5. Base64-encode the receipt data

  6. Send to brainCloud via appStore.verifyPurchase

  7. Call SKPaymentQueue.default().finishTransaction() only after brainCloud confirms

Rules to follow

  • Never use a cached receipt for purchase verification

  • Always refresh the receipt after StoreKit delivers a new transaction

  • Always call finishTransaction only after brainCloud has confirmed the purchase

Summary

Detail

Warning message

"No items were processed in transaction [storeId: itunes]"

Root cause

The in_app array in the submitted receipt is empty

Why it's empty

A stale or cached receipt was submitted; the purchase only appears in latest_receipt_info

brainCloud behavior

Logs APP_WARNING, returns resultCode: 0, awards nothing

Fix

Refresh the receipt client-side after every purchase before calling verifyPurchase

Hook script impact

Guard against empty transactionDetails to prevent null reference errors

Did this answer your question?