How do I test purchases without real money?
Start with the Test Store: it needs no App Store or Google Play account and works in seconds. Then test with each store's own sandbox: App Store sandbox accounts, StoreKit testing in Xcode (after you give RevenueDot Xcode's certificate), and Google Play license testers. RevenueDot marks all of these purchases as sandbox, so they stay out of your production numbers and webhooks carry "environment": "SANDBOX".
App Store and Google Play support is tested against mocked Apple and Google APIs only. No real sandbox purchase has run end to end yet (2026-09-30). Please report what you find.
Test Store: no store account needed#
- Create an app with
type: test_store, or run the seed script. - Use its
test_key as the SDK's API key and your server as the proxy URL. - Buy. The SDK shows a Test Store dialog and posts a
fetch_tokenof the formtest_<ms>_<id>.
You can also post a purchase yourself:
curl -s http://localhost:8787/v1/receipts \
-H "Authorization: Bearer $TEST_KEY" -H "Content-Type: application/json" \
-d "{\"app_user_id\":\"user_1\",\"fetch_token\":\"test_$(date +%s)000_demo\",\"product_id\":\"pro_monthly\",\"price\":9.99,\"currency\":\"USD\"}"To test what happens later in a subscription's life, simulate it with your secret key. scenario is one of purchase, trial, trial_conversion, renewal, cancel, billing_issue, refund or expire:
curl -s -X POST http://localhost:8787/v2/projects/$PROJECT_ID/test_purchases \
-H "Authorization: Bearer $SECRET_KEY" -H "Content-Type: application/json" \
-d '{"app_user_id":"user_refund","product_id":"pro_monthly","scenario":"refund"}'The answer lists the events it produced, here "event_types":["INITIAL_PURCHASE","CANCELLATION"], and your webhooks receive them. See Test Store.
Test Store runs work with the native SDKs too: the unmodified RevenueCat iOS SDK 5.92 on the iPhone simulator and Android SDK 10.24 on the Android emulator buy through the SDK's Test Store dialog against RevenueDot. purchases-js and React Native (Expo Go or web) work as well.
App Store sandbox#
- Connect the app: set its
bundle_idand add the App Store in-app purchase key. See Connect the App Store. - Create a sandbox Apple account in App Store Connect (Apple docs).
- Run a development or TestFlight build and buy with that account.
Sandbox transactions are signed by Apple, so RevenueDot verifies them like production ones and stores them with is_sandbox: true. Sandbox subscriptions renew on Apple's shortened schedule, and renewals reach RevenueDot through App Store Server Notifications. Put the notification URL in App Store Connect's Sandbox Server URL too. See Why are store notifications not arriving?
StoreKit testing in Xcode#
Xcode signs local test transactions with its own certificate, not Apple's (Apple docs). RevenueDot refuses them with code 7103 until you give it that certificate:
- Open your
.storekitconfiguration file in Xcode and choose Editor → Save Public Certificate. - Store the certificate on the app as the
xcode_certificatecredential. PEM text or base64 DER both work:ShellCERT=$(base64 < StoreKitTestCertificate.cer | tr -d '\n') curl -s -X POST http://localhost:8787/v2/projects/$PROJECT_ID/apps/$APP_ID \ -H "Authorization: Bearer $SECRET_KEY" -H "Content-Type: application/json" \ -d "{\"app_store\":{\"xcode_certificate\":\"$CERT\"}}" - Buy in the simulator. RevenueDot now accepts the local transactions.
Use this only on a development server. Anyone with the certificate can sign transactions it will accept.
Google Play license testers#
- Connect the app: set its
package_nameand add the service account. See Connect Google Play. - Add tester accounts under License testing in Play Console, and publish the app to an internal testing track (Google docs).
- Install from the track and buy with a tester account. Google uses test cards and shortened renewal periods.
RevenueDot reads the purchase from the Play Developer API and acknowledges it. Google tells RevenueDot it is a test purchase, so it is stored as sandbox.
Keep test purchases apart#
- Set
sandbox_transfer_behavioron the project if testers share devices and you want restores to behave differently in sandbox. See How do I restore purchases? - Point a webhook at a staging backend with
environment: "sandbox", and your production webhook atenvironment: "production". See Webhooks.