Guide · Chapter 3 of 4

Plan changes and linked purchase tokens

When a Google Play subscriber upgrades, downgrades, or re-subscribes, Play does not edit the old purchase. It issues a new purchase token and points it back at the one it replaced. Getting the entitlement right means following that pointer exactly once.

What Play hands you

The plan change itself is launched from your app through Google Play Billing, with the replacement mode you choose; Play calculates any proration. Tierux's part starts when the new token reaches the server. Its subscriptionsv2 resource carries a linkedPurchaseToken naming the superseded token, and Tierux reads that field from the query response.

Tierux does not rank your plans or decide which change is an upgrade. Each token's freshly verified Play state is treated as authoritative, and the old entitlement is retired based on that state alone.

Two routes to the same result

The new token can reach Tierux first through either input, and both are handled.

Your app verifies the new token

The usual path: after the purchase completes, the client sends the new token to the verify endpoint. Tierux queries Play, sees linkedPurchaseToken, and looks up the purchase it previously recorded for the old token. Then:

Play's notification arrives first

A SUBSCRIPTION_PURCHASED notification (or a recovered, renewed, or restarted one) can carry the new token before your app has verified it. Tierux has no purchase record for that token yet, so for those four types it queries Play for the token's own state, follows linkedPurchaseToken back to the recorded purchase, and carries the user and entitlement forward from it. It then stores a purchase record for the new token — with an encrypted copy of the token so later refreshes can re-verify it — and points the entitlement at the new token.

If that Play query fails, Tierux cannot tell a plan change from an unknown token, so the RTDN endpoint answers 503 and Pub/Sub redelivers. A token that Play links to nothing Tierux recorded is acknowledged as an unknown purchase. Before changing the entitlement, Tierux re-checks that the new token is not already claimed by a different user; if it is, the change is skipped and logged.

Retiring the old entitlement

On either route, the superseded entitlement is switched off once the new token verifies as live:

// src/services/entitlementService.ts (verify path)
if (verification.linkedPurchaseToken && active) {
  await supersedeLinkedPurchase(
    this.store,
    input.appId,
    verification.linkedPurchaseToken,
    mapping.entitlementId,
    input.userId,
  );
}

Retiring writes the old entitlement to cancelled with access off. Three cases leave it alone:

Which products map to which entitlement ids is your product mapping — chapter 5 of the verification guide covers it. A cross-entitlement change (Basic to Pro) cancels Basic and activates Pro; a same-entitlement change keeps one record.

Late events on the old token

After a plan change, Play can still send notifications about the old token: an expiry, or a voided purchase for the prorated remainder of an upgrade. If they were applied, they would switch off the subscriber's new plan.

Tierux compares a Google Play notification's token with the token the entitlement currently points at. An event whose token hash differs is acknowledged with outcome superseded_purchase and makes no change. This guard is what makes the re-pointing step above load-bearing, and it sits in front of the idempotency and ordering checks described in the notifications chapter.

On the App Store

Apple models plan changes within a subscription group and has no Play-style linkedPurchaseToken. Tierux treats Apple's renewal-preference change notification as informational: it writes nothing to the entitlement. App Store support is implemented with limitations — see the platform support matrix.

Related reading

Glossary: linkedPurchaseToken

The field, and why it is not present on every return to a subscription.

Glossary: Proration

Play's replacement modes and how they decide timing and charge.

Blog: How plan changes really work

The same mechanism told as a story, with the failure modes it prevents.

Guide: Mapping products to entitlements

Why a same-entitlement change keeps one record and a cross-entitlement change swaps two.

Feature: Purchase verification

Verifying the initial purchase and each plan change server-side.

← Back to the subscription lifecycle guide

Plan changes without double entitlements

Free tier — unlimited apps, 1 paywall. No credit card, no revenue share.

Start free