What does the Google Play notification SUBSCRIPTION_PAUSED mean?

The Google Play notification SUBSCRIPTION_PAUSED means a subscription's pause has started, so the customer should have no access until it resumes.

Quick facts#

Notification subscriptionNotification.notificationType 10, SUBSCRIPTION_PAUSED
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 paused.

What triggers it#

  • The pause the customer scheduled has reached the end of the paid period and now takes effect.
  • The subscription resource has state SUBSCRIPTION_STATE_PAUSED, with autoRenewEnabled true. The pausedStateContext says when it renews again.
  • While paused the customer has no access and pays nothing.

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. Remove access until the subscription resumes.
  3. Show the expected resume date from pausedStateContext.
  4. Wait for SUBSCRIPTION_RECOVERED when it resumes, or SUBSCRIPTION_ON_HOLD if the payment fails on resume.
  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":10,"purchaseToken":"PURCHASE_TOKEN"}})).toString("base64") } };

function decide(body) {
  const n = JSON.parse(Buffer.from(body.message.data, "base64").toString("utf8"));
  if (!(n.subscriptionNotification?.notificationType === 10)) return "ignore";
  return "remove access until it resumes, show the resume date";
}

console.log(decide(body));

Run-checked: npm run check:snippets runs this snippet with Node and compares its output with remove access until it resumes (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 ends access now, stores the auto-resume date from the paused state and keeps the scheduled date. The scheduler then sends EXPIRATION with expiration_reason: SUBSCRIPTION_PAUSED.

Source#

Checked: 2026-10-03

Edit this page on GitHub ↗ View as Markdown Last updated