What does the Google Play notification SUBSCRIPTION_REVOKED mean?

The Google Play notification SUBSCRIPTION_REVOKED means a subscription was taken away before its expiration time, so access must end now.

Quick facts#

Notification subscriptionNotification.notificationType 12, SUBSCRIPTION_REVOKED
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 subscription has been revoked from the user before the expiration time.

What triggers it#

  • Your backend revoked it with purchases.subscriptionsv2.revoke, or the purchase was charged back.
  • The subscription resource has subscriptionState set to SUBSCRIPTION_STATE_EXPIRED.
  • Unlike a cancellation, the customer does not keep access to the period end.

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. Revoke the customer's entitlement immediately.
  3. Record the revocation for support and refund reports.
  4. Offer a new subscription if the revocation was in error.
  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":12,"purchaseToken":"PURCHASE_TOKEN"}})).toString("base64") } };

function decide(body) {
  const n = JSON.parse(Buffer.from(body.message.data, "base64").toString("utf8"));
  if (!(n.subscriptionNotification?.notificationType === 12)) return "ignore";
  return "revoke access immediately";
}

console.log(decide(body));

Run-checked: npm run check:snippets runs this snippet with Node and compares its output with revoke access immediately (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. RevenueDot marks the current period refunded at the event time and cuts its expiry to that time. It sends CANCELLATION with cancel_reason: CUSTOMER_SUPPORT and a negative price, the same as a refund. If Google no longer knows the token, it refunds from what it stored.

Source#

Checked: 2026-10-03

Edit this page on GitHub ↗ View as Markdown Last updated