What does the Google Play notification ONE_TIME_PRODUCT_PURCHASED mean?

The Google Play notification ONE_TIME_PRODUCT_PURCHASED means a customer bought a one-time product.

Quick facts#

Notification oneTimeProductNotification.notificationType 1, ONE_TIME_PRODUCT_PURCHASED
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 one-time product was successfully purchased by a user.

What triggers it#

  • A customer completed the purchase of an in-app product.
  • Google sends it only if you chose to receive one-time product purchase events when you set up notifications.
  • The message carries the sku and the purchaseToken.

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. Call the products API with the sku and token, check the purchase state, and deliver the item once.
  3. Acknowledge or consume the purchase so Google does not refund it.
  4. Key delivery on the order so a repeat message does not give the item twice.
  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","oneTimeProductNotification":{"version":"1.0","notificationType":1,"purchaseToken":"PURCHASE_TOKEN","sku":"coins_100"}})).toString("base64") } };

function decide(body) {
  const n = JSON.parse(Buffer.from(body.message.data, "base64").toString("utf8"));
  if (!(n.oneTimeProductNotification?.notificationType === 1)) return "ignore";
  return "verify, deliver once, acknowledge";
}

console.log(decide(body));

Run-checked: npm run check:snippets runs this snippet with Node and compares its output with deliver once (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 fetches the product purchase for the sku and token, skips a purchase that is still pending, stores it under its order ID and acknowledges it. A new purchase gives NON_RENEWING_PURCHASE. The consumable flag comes from the product's type in your catalog.

Source#

Checked: 2026-10-03

Edit this page on GitHub ↗ View as Markdown Last updated