What does the Google Play notification SUBSCRIPTION_PURCHASED mean?

The Google Play notification SUBSCRIPTION_PURCHASED means a new subscription was purchased and has a new purchase token.

Quick facts#

Notification subscriptionNotification.notificationType 4, SUBSCRIPTION_PURCHASED
Where Google Play real-time developer notifications (Pub/Sub, DeveloperNotification)
Sent by Google Play, as a Cloud Pub/Sub push to your endpoint
What Google says A new subscription was purchased.

What triggers it#

  • A customer bought a subscription in your app or in the Play Store.
  • A resubscribe after the old subscription expired is a new purchase with a brand new purchase token and no linkedPurchaseToken.
  • An upgrade, downgrade or signup after cancelling from your app creates a new token with linkedPurchaseToken pointing to the old one.

What your server should do#

  1. Do not trust the message for the state. Google says a notification only tells you the purchase state changed; call the Google Play Developer API (purchases.subscriptionsv2.get) with the purchase token to get the full state.
  2. Call purchases.subscriptionsv2.get, check subscriptionState is SUBSCRIPTION_STATE_ACTIVE, and grant access.
  3. Acknowledge the purchase within three days. Google says an unacknowledged purchase is refunded and revoked automatically.
  4. Use linkedPurchaseToken or outOfAppPurchaseContext to connect the new token to the right customer.
  5. Answer 2xx once you have handled the message, and skip a messageId you have seen: Google recommends checking the uniqueness of message IDs so a redelivery does not make a second API call.

Example#

JavaScript
// A Pub/Sub push body: the notification is base64 JSON in message.data.
const body = { message: { messageId: "136969346945", data: Buffer.from(JSON.stringify({"version":"1.0","packageName":"com.example.app","eventTimeMillis":"1790800914000","subscriptionNotification":{"version":"1.0","notificationType":4,"purchaseToken":"PURCHASE_TOKEN"}})).toString("base64") } };

function decide(body) {
  const n = JSON.parse(Buffer.from(body.message.data, "base64").toString("utf8"));
  if (!(n.subscriptionNotification?.notificationType === 4)) return "ignore";
  return "fetch the subscription, grant access, acknowledge within three days";
}

console.log(decide(body));

Run-checked: npm run check:snippets runs this snippet with Node and compares its output with acknowledge within three days (checked 2026-10-03).

How RevenueDot handles it#

RevenueDot answers every handled message with 2xx and every temporary failure with 5xx so Pub/Sub redelivers it. For subscription types it re-reads the subscription from Google with purchases.subscriptionsv2.get and applies that state, and it acknowledges a new purchase if the app has not. A purchase RevenueDot has not seen is applied only when the app's Track new purchases from server-to-server notifications setting is on. A token RevenueDot has not stored gives an INITIAL_PURCHASE event; a replacement token joins the customer of its linkedPurchaseToken, and the old chain ends with a PRODUCT_CHANGE event instead of a CANCELLATION or EXPIRATION. RevenueDot acknowledges the purchase itself, and if that fails it answers 5xx so Pub/Sub retries.

Source#

Checked: 2026-10-03

Edit this page on GitHub ↗ View as Markdown Last updated