Sunstone Apps
← Back to blog

Android monetization

How to validate a Google Play test purchase with RevenueCat

A purchase that works on the device is only the first signal. Real validation ties together Play Console, RevenueCat, SDK identity, app delivery, and observability.

Published: 7 min readUpdated:
OpenGraph preview image for this article. How to validate a Google Play test purchase with RevenueCat

Validating an in-app purchase is not the same as tapping the button and seeing credits appear.

On Android, the flow crosses three different systems:

  • Google Play processes the purchase.
  • RevenueCat validates the receipt and updates the commercial state.
  • Sentry shows whether the flow produced a real app error.

If you only look at one of them, you can close the test with a blind spot.

1. First prove the product loads

The first signal is the in-app store showing the product with localized pricing.

That proves:

  • The app is talking to the billing client.
  • The product exists for that account and track.
  • The offer is available in the tester’s country.

But it does not prove RevenueCat credentials. A visible price should come from the purchase provider, not hardcoded app copy. It still does not mean the receipt can be validated after checkout.

2. Purchase with a test card

At checkout, confirm that the sheet comes from Google Play and that the payment method is a test method.

The goal is not revenue. It is to exercise the same operational path as a real purchase without charging the tester.

After confirmation, the app should grant the benefit only if the purchase completed. For consumables, such as credit packs, this is especially important: cancelled, unavailable, or failed purchases should not grant rewards.

3. Do not skip Google Cloud

Credential errors often start before the purchase test: the service account does not yet have the full path between Google Cloud, Play Console, and RevenueCat.

The safe minimum is:

  • Have a dedicated or clearly identified Google Cloud project for app billing.
  • Enable the Google Play Android Developer API, used to validate and consume purchases.
  • Enable Cloud Pub/Sub if you use Google developer notifications.
  • Create a service account for RevenueCat.
  • Generate the JSON key and upload it only to RevenueCat.
  • Grant enough permissions to that service account in Play Console.

The sensitive part is the key. It should not go into Git, a blog post, a ticket, or a shared screenshot. Public documentation gets the process and symptoms. The secret stays in Google Cloud and RevenueCat.

4. Confirm the order in Play Console

The most direct place to confirm the test sale is:

Play Console > Order management

Look for the most recent app order and confirm:

  • Date and time match the test.
  • Product is correct.
  • Type is One-time product, when it is a one-time purchase.
  • Status is Processed.
  • Total matches the expected price.

For a test purchase, Estimated revenue can show 0.00. That does not invalidate the test. The important part is that the order is processed and attached to the right product.

5. Validate RevenueCat credentials

After connecting the Google Play service account to RevenueCat, use the validation button on the Android app settings page in RevenueCat.

The important checks are:

subscriptions_api_permissions: SUCCESS
inapp_products_permissions: SUCCESS
monetization_api_permissions: SUCCESS

Even if the app does not use subscriptions, the subscriptions check can appear because RevenueCat validates broad Play Developer API permissions. If it fails, review the service account permissions in Play Console and allow time for Google propagation.

That was the failure we saw in testing: the product existed and checkout opened, but RevenueCat still did not have enough permission to complete purchase validation.

6. Find the sandbox purchase in RevenueCat

Test purchases can exist in RevenueCat and still look missing if you only check aggregated lists.

The most reliable path is to capture the App User ID used by the SDK. In an instrumented app, look for a log like:

[store/revenuecat] purchase completed ... "appUserId":"$RCAnonymousID:..."

Then open that customer profile in RevenueCat and enable Show sandbox data.

For consumables, do not expect an active entitlement. A credit pack can appear as:

  • History: Made a purchase of Small credits pack.
  • Loose product: Unattached products.
  • Counter: Purchased 2x.

This avoids a false diagnosis. The purchase is not necessarily absent; it may be hidden in the non-sandbox view or outside the aggregated summary.

7. Test refunds with entitlement removal

Refunding a non-consumable has one easy-to-miss detail: returning the money is not always the same as removing access. In Play Console, the refund screen can warn that the customer will be refunded but will keep the product or subscription. To test revocation for something like noads.lifetime, also select Remove entitlement.

After that, validate three places:

  • Play Console: the order should show refunded or cancelled.
  • RevenueCat: the correct customer should no longer list the entitlement as active.
  • App: the benefit should disappear after a customer refresh.

The last point is where tests often lie. One device that tapped Restore purchases can update immediately, while another device that has been open for hours still uses the locally cached customer. The app should not depend only on a manual button. A lightweight getCustomerInfo() on boot and when the app returns to foreground reduces that delay and lets refunds with entitlement removal show up without asking the user to find a support-oriented action.

8. Use Sentry as negative confirmation

After a successful purchase, check that Sentry did not receive a new purchase error.

This is a case where absence of an event matters. If the previous purchase attempt created something like [shop] purchase failed, the new test should pass without creating a similar regression.

The care point is not confusing an old issue with the current test. Compare the event timestamp with the processed order time in Play Console.

9. Do not finish from the wrong dashboard

Aggregated dashboards can lag or filter test purchases. If the RevenueCat overview does not show the transaction immediately, that is not automatically a failure.

Trust order for a smoke test:

  1. Processed order in Play Console.
  2. Valid RevenueCat credentials.
  3. RevenueCat customer profile shows the purchase with Show sandbox data.
  4. App granted the correct benefit.
  5. Sentry received no new error.
  6. Aggregated dashboard catches up later.

Final checklist

Before saying the test purchase is validated:

  • The app was installed from Google Play.
  • The product appeared with localized pricing.
  • The shown price came from the purchase provider and matched Google Play checkout.
  • Checkout used a test card.
  • Google Cloud has the Android Developer API and Pub/Sub when the integration uses them.
  • The service account was created, linked in Play Console, and uploaded to RevenueCat.
  • The order appeared in Play Console as Processed.
  • The order product matches the expected SKU.
  • RevenueCat showed valid credentials.
  • The App User ID used by the SDK was checked in logs.
  • The RevenueCat customer profile was opened with Show sandbox data.
  • The app granted the benefit only after purchase completion.
  • Non-consumable refund was tested with Remove entitlement, not only money returned.
  • The app refreshes customer state on boot, foreground, or a clear manual action such as Restore purchases.
  • Sentry received no new error at the test time.

This checklist does not replace restore, refund, cancellation, and unavailable-product tests. It only closes the basic question: “does one happy-path purchase, delivered through Google Play, work end to end?”.

Do not trust one dashboard alone

Sandbox purchases are noisy enough that one dashboard rarely tells the whole story. Play Console can show an order, RevenueCat can show a customer, the SDK can log an app user ID, and the app can still fail to unlock locally. The validation needs to connect those signals.

A good purchase note should answer four questions:

  • Did Google Play create an order for the expected product?
  • Did RevenueCat receive or refresh the transaction?
  • Which app user ID did the SDK use on the device?
  • What local unlock or entitlement state did the app apply after purchase?

If any answer is missing, the test is incomplete. It may still be useful, but it should not be called validated.

Common sandbox traps

The most common trap is testing with the wrong Play account. The app can be installed, the product can look configured, and billing can still return unavailable because the active store account is not the invited tester.

Another trap is reading aggregated customer lists without enabling sandbox data or inspecting the exact profile. Consumables can also look different from entitlements, especially when they are delivered as one-time products. That is why the validation should include the order, RevenueCat profile, SDK identity, and app state.

Make the negative paths first-class

A purchase flow is only robust when cancelled, unavailable, failed, and delivery-error states are visible. The app should not grant benefits in finally, should not treat a provider exception as success, and should not hide delivery failure behind a generic toast.

For indie apps, this is less about enterprise architecture and more about support. When a tester says “I bought it and nothing happened,” the team needs a trail that explains whether the store, provider, SDK identity, or app delivery step failed.

Local delivery should be idempotent

Purchase delivery should tolerate retries. If the provider callback runs twice, the app should not grant duplicate non-consumable benefits. If a consumable delivery is interrupted, the app should be able to resume or reconcile without losing the purchase. That usually means recording enough local state to know what was already granted.

This is not overengineering. Mobile purchase flows cross process boundaries, network calls, app lifecycle changes, and external store UI. Idempotency is what keeps recovery boring.

Conclusion

A sandbox purchase is validated only when the store order, RevenueCat customer, SDK identity, and app delivery state tell the same story. Anything less can still be a useful clue, but it should not close the checklist.