Restore Apple Store Purchases
POST https://api.botsi.com/v2/purchases/apple-store/restoreGrant a Profile the access its App Store subscription carries. Use it behind a "Restore Purchases" button, after a reinstall, or when the user moves to a new device. It takes a StoreKit 2 original transaction ID, not an app receipt.
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.
When to call it#
Call it only when StoreKit reports at least one transaction in Transaction.currentEntitlements. If StoreKit reports nothing, there's nothing to restore, so read the Profile with Get a Profile instead.
Request body#
Send the original transaction ID, not the transaction's own id. Apple matches the subscription on the original ID.
There's no environment field. Botsi looks the transaction up in production first, then in sandbox.
# Authorization: $BOTSI_SECRET_KEY or $BOTSI_PUBLIC_KEY
curl -X POST "https://api.botsi.com/v2/purchases/apple-store/restore" \
-H "Authorization: $BOTSI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "fff3c120-0ca8-480f-9b19-3955a5428e39",
"originalTransactionId": "2000000261699248"
}'What a restore does#
Botsi asks Apple for the subscription behind the transaction, then handles one of four cases:
Response#
A successful restore returns 200 with the Profile after the restore. It's the same shape Validate Apple 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": "app_store",
"sourceProductId": "premium_annual",
"expiresAt": "2027-10-07",
"willRenew": true,
"isLifetime": false
}
},
"subscriptions": {
"premium_annual": {
"isActive": true,
"store": "app_store",
"sourceProductId": "premium_annual",
"expiresAt": "2027-10-07",
"willRenew": true,
"isLifetime": false
}
},
"nonSubscriptions": {}
}
}The entitlements above are trimmed to a few fields. The response carries every field listed under Entitlement fields.
Errors#
For example, a transaction Apple has no subscription for returns:
{
"error": "Apple has no subscription for originalTransactionId: 2000000261699248",
"code": "nothing_to_restore"
}