Agent Wranglers

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

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.