Skip to content

Search the documentation by title, section, or page text.

Restore Google Play Subscriptions

POST https://api.botsi.com/v2/purchases/play-store/restore

Grant a Profile the access its Google Play subscriptions carry. It's the Google Play counterpart of Restore Apple Store Purchases. Use it behind a "Restore Purchases" button, after a reinstall, or when the user moves to a new device.

This route accepts $BOTSI_SECRET_KEY or $BOTSI_PUBLIC_KEY in the Authorization header, with no Bearer prefix. The sample sends the secret key. From inside the app, send the public key. See Authentication.

What to send#

Send every subscription that Play Billing's queryPurchasesAsync(ProductType.SUBS) returns for the signed-in account, one entry per purchase.

Request body#

ParameterTypeRequiredDescription
profileIdstringRequiredBotsi profile ID of the user restoring
purchasesarrayRequiredBetween 1 and 20 subscription purchases, from queryPurchasesAsync(ProductType.SUBS)
purchases[].productIdstringRequiredSubscription product ID, from Purchase.getProducts()
purchases[].purchaseTokenstringRequiredThe purchase token, from Purchase.getPurchaseToken()
# Authorization: $BOTSI_SECRET_KEY or $BOTSI_PUBLIC_KEY
curl -X POST "https://api.botsi.com/v2/purchases/play-store/restore" \
  -H "Authorization: $BOTSI_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "fff3c120-0ca8-480f-9b19-3955a5428e39",
    "purchases": [
      {
        "productId": "premium_annual",
        "purchaseToken": "algojlnkodhhjceoicbpjngh.AO-J1Owvcga8j2uUoKEpn5AnvpSFr8dxEFm0c6qk5"
      }
    ]
  }'

What a restore does#

Botsi processes the purchases one at a time, in the order you send them.

Tokens Google doesn't recognize are skipped, not failed. That covers tokens Google doesn't know (a 404 from Google) and tokens it no longer reports, such as a subscription that expired long ago (a 410). The restore fails only when every token is skipped.

Each recognized purchase is handled the same way as an Apple restore:

CaseWhat happens
The Profile already owns the purchaseNothing changes. Calling repeatedly is safe
A different Botsi Profile owns the purchase. For example, after a reinstall or on a second deviceThe restoring Profile receives that Profile's Access Level, subscription state, and custom attributes, and the two Profiles are linked. The original Profile keeps its access
Botsi has a record of the purchase, with no Profile attachedThe purchase history is attached to the restoring Profile
Botsi has never seen the purchase. For example, it was bought before your app integrated BotsiBotsi rebuilds its history from Google and grants access

Response#

A successful restore returns 200 with the Profile after the restore. It's the same shape Validate Google Play Store Purchase returns: the Profile object from Get a Profile, without custom.

{
  "ok": true,
  "data": {
    "profileId": "fff3c120-0ca8-480f-9b19-3955a5428e39",
    "appUserId": "user-123",
    "state": "subscribed",
    "totalRevenueUsd": 49.99,
    "accessLevels": {
      "premium": {
        "isActive": true,
        "store": "play_store",
        "sourceProductId": "premium_annual",
        "sourceBasePlanId": "annual-base",
        "expiresAt": "2027-10-07",
        "willRenew": true
      }
    },
    "subscriptions": {
      "premium_annual": {
        "isActive": true,
        "store": "play_store",
        "sourceProductId": "premium_annual",
        "sourceBasePlanId": "annual-base",
        "expiresAt": "2027-10-07",
        "willRenew": true
      }
    },
    "nonSubscriptions": {}
  }
}

The entitlements above are trimmed to a few fields. The response carries every field listed under Entitlement fields.

Errors#

StatuscodeCause
400bad_requestprofileId is missing, purchases is empty or has more than 20 items, or an item is missing productId or purchaseToken. For example, purchases must contain no more than 20 elements
400bad_requestYour app's Google Play connection isn't set up. The message is No settings found or Android settings doesn't have packageName
401unauthorizedThe Authorization header is missing or holds an unknown key
404not_foundNo Profile with that ID belongs to your app. A Profile owned by another app returns the same response
404nothing_to_restoreGoogle Play has no subscription for any of the purchase tokens

For example, a request where every token is skipped returns:

{
  "error": "Google Play has no subscription for any of the purchase tokens.",
  "code": "nothing_to_restore"
}