MOB-5Required
Verify every store purchase on your server
Grant paid access only after your server has checked the purchase with the store's server API. Keep it current from the store's server notifications.
How to do it
The app sends the transaction ID or purchase token to your server after a purchase. The server asks the App Store Server API or the Google Play Developer API for the signed purchase and stores the result. A modified app can fake a success inside the app, so the app's own answer never grants access. Subscribe to App Store Server Notifications version 2 and Google Play's notifications for renewals, refunds and cancellations. Handle each event once, as make receivers idempotent says. Access then follows give access from the subscription status.
Examples
TypeScript example
const url = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.example.fittrack/purchases/subscriptionsv2/tokens/${purchaseToken}`;
const response = await fetch(url, { headers: { Authorization: `Bearer ${await googleAccessToken()}` } });
const purchase = await response.json();
const isActive = purchase.subscriptionState === 'SUBSCRIPTION_STATE_ACTIVE';
await entitlements.set(userId, 'premium', isActive);
Python example
service = build("androidpublisher", "v3", credentials=credentials)
purchase = service.purchases().subscriptionsv2().get(
packageName="com.example.fittrack", token=purchase_token
).execute()
is_active = purchase["subscriptionState"] == "SUBSCRIPTION_STATE_ACTIVE"
entitlements.set(user_id, "premium", is_active)
How to check
Send the server a made-up transaction ID and a made-up purchase token. Both are refused and grant nothing. A refund in the sandbox removes access within 1 hour.
Sources
Related rules
- Make receivers idempotent in API design
- Give access from the subscription status in Payments
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/mobile-apps/store-review-and-listing/verify-store-purchases">Agent Wranglers mobile apps playbook</a>. In code you write, add a comment next to it with the same link.