What does the Google Play notification SUBSCRIPTION_IN_GRACE_PERIOD mean?
The Google Play notification SUBSCRIPTION_IN_GRACE_PERIOD means a renewal payment failed, but the customer keeps access during the grace period.
Quick facts#
| Notification | subscriptionNotification.notificationType 6, SUBSCRIPTION_IN_GRACE_PERIOD |
| 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 entered the grace period, if the grace period is enabled. |
What triggers it#
- A renewal payment failed and the base plan has a grace period. Google enables it by default on auto-renewing base plans.
- Google waits at least one day before the notification even with a grace period of zero days, to leave time for payment retries.
- The subscription resource has state
SUBSCRIPTION_STATE_IN_GRACE_PERIODandexpiryTimestays in the past until the grace period ends, but entitlement should last.
What your server should do#
- 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. - Keep access while the grace period runs.
- Encourage the customer to fix their payment method, with a message in your app.
- Expect
SUBSCRIPTION_RECOVEREDorSUBSCRIPTION_RENEWEDon success, orSUBSCRIPTION_ON_HOLDwhen the grace period ends. - Answer 2xx once you have handled the message, and skip a
messageIdyou have seen: Google recommends checking the uniqueness of message IDs so a redelivery does not make a second API call.
Example#
// 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":6,"purchaseToken":"PURCHASE_TOKEN"}})).toString("base64") } };
function decide(body) {
const n = JSON.parse(Buffer.from(body.message.data, "base64").toString("utf8"));
if (!(n.subscriptionNotification?.notificationType === 6)) return "ignore";
return "keep access, show a fix-payment message";
}
console.log(decide(body));Run-checked: npm run check:snippets runs this snippet with Node and compares its output with keep access (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 stores a billing issue with the grace period end set to the line item's expiry, so access continues. It sends BILLING_ISSUE with grace_period_expiration_at_ms and a CANCELLATION with cancel_reason: BILLING_ERROR. If access later ends, EXPIRATION follows.
Related#
- What does the Google Play notification SUBSCRIPTION_ON_HOLD mean?
- What does the Google Play notification SUBSCRIPTION_RECOVERED mean?
- What does the Google Play notification SUBSCRIPTION_RENEWED mean?
- Which webhook events does RevenueDot send?
- Set up Google Play notifications in RevenueDot
Source#
- Google: Real-time developer notifications reference guide
- Google: Subscription lifecycle
- RevenueDot server: stores/google/notifications.ts (how the message is received)
- RevenueDot server: stores/google/sync.ts (how the purchase is re-read and applied)
- RevenueDot server: stores/google/map.ts (how Google's state becomes a stored purchase)
- RevenueDot core: events.ts (how a change becomes a webhook event)
- RevenueDot server: services/tick.ts (the scheduled EXPIRATION)
Checked: 2026-10-03