What does the Google Play notification SUBSCRIPTION_DEFERRED mean?

The Google Play notification SUBSCRIPTION_DEFERRED means the billing date of a subscription was moved later, so the customer gets more time without a charge.

Quick facts#

Notification subscriptionNotification.notificationType 9, SUBSCRIPTION_DEFERRED
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's recurrence time has been extended.

What triggers it#

  • Your backend called purchases.subscriptionsv2.defer, for example for a free week as a promotion or a goodwill gesture.
  • During the deferral the customer has full access and is not charged. The renewal date is updated.
  • For prepaid plans the defer API moves the expiration time.

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. Store the new expiryTime and extend access to it.
  3. Record why the deferral was given, so support can explain it.
  4. Do not treat it as a payment.
  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":9,"purchaseToken":"PURCHASE_TOKEN"}})).toString("base64") } };

function decide(body) {
  const n = JSON.parse(Buffer.from(body.message.data, "base64").toString("utf8"));
  if (!(n.subscriptionNotification?.notificationType === 9)) return "ignore";
  return "extend access to the new expiryTime, no payment";
}

console.log(decide(body));

Run-checked: npm run check:snippets runs this snippet with Node and compares its output with no payment (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. The period start is unchanged and the end moves later, so RevenueDot sends SUBSCRIPTION_EXTENDED. No money moves on it: its price is 0.

Source#

Checked: 2026-10-03

Edit this page on GitHub ↗ View as Markdown Last updated