---
title: "What does the Google Play notification SUBSCRIPTION_PENDING_PURCHASE_CANCELED mean?"
description: "SUBSCRIPTION_PENDING_PURCHASE_CANCELED (20) means a pending subscription purchase was cancelled before it completed. Nothing was granted, so remove any pending state."
url: https://revenuedot.app/docs/notifications/google-subscription-pending-purchase-canceled
---

# What does the Google Play notification SUBSCRIPTION_PENDING_PURCHASE_CANCELED mean?

The Google Play notification SUBSCRIPTION_PENDING_PURCHASE_CANCELED means a purchase that was still pending was cancelled before it went through.

## Quick facts

| | |
|---|---|
| Notification | `subscriptionNotification.notificationType` 20, `SUBSCRIPTION_PENDING_PURCHASE_CANCELED` |
| 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 pending transaction of a subscription has been canceled. |

## What triggers it

- The customer started a purchase with a slow payment method, and it was cancelled before completing.
- The subscription never became active, so no access was ever due.
- Pending purchases are shown by Google as `SUBSCRIPTION_STATE_PENDING` until they finish.

## 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 any pending marker you kept for this purchase token.
3. Do not grant access and do not acknowledge the purchase.
4. Let the customer try again.
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":20,"purchaseToken":"PURCHASE_TOKEN"}})).toString("base64") } };

function decide(body) {
  const n = JSON.parse(Buffer.from(body.message.data, "base64").toString("utf8"));
  if (!(n.subscriptionNotification?.notificationType === 20)) return "ignore";
  return "drop the pending purchase, grant nothing";
}

console.log(decide(body));
```

*Run-checked: `npm run check:snippets` runs this snippet with Node and compares its output with `grant nothing` (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 ignores it: the message is stored, answered 2xx with status `ignored`, and no purchase or event is created. Pending subscription states are ignored the same way.

## Related

- [What does the Google Play notification SUBSCRIPTION_PURCHASED mean?](https://revenuedot.app/docs/notifications/google-subscription-purchased.md)
- [What does the Google Play notification ONE_TIME_PRODUCT_CANCELED mean?](https://revenuedot.app/docs/notifications/google-one-time-product-canceled.md)
- [What does the Google Play notification SUBSCRIPTION_EXPIRED mean?](https://revenuedot.app/docs/notifications/google-subscription-expired.md)
- [Which webhook events does RevenueDot send?](https://revenuedot.app/docs/api/webhook-events.md)
- [Set up Google Play notifications in RevenueDot](https://revenuedot.app/docs/guides/google-play.md)

## Source

- [Google: Real-time developer notifications reference guide](https://developer.android.com/google/play/billing/rtdn-reference)
- [Google: Subscription lifecycle](https://developer.android.com/google/play/billing/lifecycle/subscriptions)
- [RevenueDot server: stores/google/notifications.ts (how the message is received)](https://github.com/revenuedot/revenuedot/blob/main/apps/server/src/stores/google/notifications.ts)
- [RevenueDot server: stores/google/notifications.ts (how the message is received)](https://github.com/revenuedot/revenuedot/blob/main/apps/server/src/stores/google/notifications.ts)
- [RevenueDot server: stores/google/sync.ts (how the purchase is re-read and applied)](https://github.com/revenuedot/revenuedot/blob/main/apps/server/src/stores/google/sync.ts)

Checked: 2026-10-03
