How RTDN works
Real-time developer notifications (RTDN) are Google Play's server-to-server purchase events. Play publishes each event to a Cloud Pub/Sub topic, and your code receives it through a Pub/Sub subscription. Every message carries one base64-encoded data field that decodes to a DeveloperNotification: packageName, eventTimeMillis, and one of subscriptionNotification, oneTimeProductNotification, voidedPurchaseNotification, pendingRefundReviewNotification (a chargeback request for which you can suggest a resolution) or testNotification.
The sentence to remember from Google's reference:
“These notifications tell you only that the purchase state changed. They do not give you complete information about the purchase.”
— Android Developers, Real-time developer notifications reference guide
You get a purchaseToken (plus an orderId for voided purchases). The amount comes from a follow-up call to the Google Play Developer API — step 5.
The notification types that matter for sales:
| Notification | Type | Meaning |
|---|---|---|
subscriptionNotification | (4) SUBSCRIPTION_PURCHASED | A new subscription was purchased |
(2) SUBSCRIPTION_RENEWED | An active subscription was renewed | |
(1) SUBSCRIPTION_RECOVERED | Recovered from account hold or resumed from pause | |
(3) SUBSCRIPTION_CANCELED · (13) SUBSCRIPTION_EXPIRED · (12) SUBSCRIPTION_REVOKED | Cancelled, expired, or revoked before the expiration time | |
oneTimeProductNotification | (1) ONE_TIME_PRODUCT_PURCHASED | A one-time product was purchased |
(2) ONE_TIME_PRODUCT_CANCELED | A pending one-time purchase was cancelled by the user | |
voidedPurchaseNotification | productType, refundType | A purchase was voided (refund, chargeback); carries the orderId |
The full list — grace period, account hold, pauses, price changes — is in the reference guide linked below.
Step 1: create a Pub/Sub topic
In the Google Cloud console, open Pub/Sub and create a topic in any project you control. Note its full name; it looks like projects/your-project-id/topics/play-rtdn.
Step 2: let Google Play publish to it
- In the Cloud console, open Pub/Sub and find your topic.
- Open its permissions.
- Add the service account
google-play-developer-notifications@system.gserviceaccount.comwith the role Pub/Sub Publisher. - Click Save.
If your organization restricts sharing to its own domain, Google notes that you must add an exception for this Google Play service account, or the permission can't be granted.
Step 3: connect the topic in Play Console
- Open Google Play Console and select your app.
- Go to Monetize › Monetization setup.
- In the Real-time developer notifications section at the top, check Enable real-time notifications.
- In Topic name, enter the full topic name:
projects/{project_id}/topics/{topic_name}. - Choose what to receive. “Get notifications for subscriptions and all voided purchases” leaves out one-time product purchases; for sale alerts on one-time products, choose “Get all notifications for subscriptions and one-time products”.
- Click Save changes, then Send test message.
If the test publish fails, Google says to check that the topic name is exact and that the service account has Pub/Sub Publisher access. RTDN is set per app, so repeat this for each app — every app can point at the same topic.
Step 4: receive the messages
Attach a subscription to the topic. Google's Pub/Sub documentation describes the two kinds: pull subscriptions “use a subscriber client to request messages from the Pub/Sub server”, and push subscriptions “use the Pub/Sub server to initiate requests to your subscriber application to deliver messages”. With push, a successful HTTP response from your endpoint acknowledges the message; with pull, acknowledge each message you've handled, or Pub/Sub delivers it again.
Pub/Sub “offers at-least-once delivery with no ordering guarantees”, so expect the occasional duplicate. Google's RTDN guide recommends checking messageId uniqueness to avoid processing duplicates and wasting Developer API quota.
// Push endpoint: Pub/Sub POSTs {"message": {"data": "<base64>", "messageId": "…"}, "subscription": "…"}
export async function onPush(request) {
const { message } = await request.json();
if (await alreadySeen(message.messageId)) return new Response(null, { status: 204 });
const note = JSON.parse(atob(message.data)); // DeveloperNotification
if (note.testNotification) return new Response(null, { status: 204 });
await enqueueLookup(note.packageName, note.subscriptionNotification ?? note.oneTimeProductNotification ?? note.voidedPurchaseNotification);
return new Response(null, { status: 204 }); // 2xx acknowledges the message
}
For a public push endpoint, also turn on authentication for the push subscription so your endpoint can reject requests that didn't come from Pub/Sub.
Step 5: look up the purchase
Call the Google Play Developer API with credentials that can access the app — a service account added in Play Console, or an OAuth token with the androidpublisher scope:
- Subscriptions:
purchases.subscriptionsv2.getwith thepurchaseTokenreturns the subscription state and its line items, each with itslatestSuccessfulOrderIdand recurring price. The recurring price leaves out discounts and taxes; the order below has the amount actually paid. - One-time products:
purchases.products.getwith the product ID (sku) and token returns theorderId, quantity and region, but no amount. - The amount:
orders.getwith theorderIdreturns the order'stotal,tax,developerRevenueInBuyerCurrencyand line items withlistingPrice. - Refunds: a
voidedPurchaseNotificationalready carries theorderIdand whether it was a full or partial (quantity-based) refund.
With the amount in hand, send the alert wherever you like — Slack, a push notification, or a menu-bar app.
If you'd rather not run a Cloud project
RevBell runs the topic and the receiver for you. In Play Console you paste one RevBell topic, projects/reviewbell-play-production/topics/reviewbell-rtdn, instead of creating your own:
- For each notification, RevBell's server stores only the package name, notification type, purchase token, product ID, order ID when present, and event time, for at most 7 days. It never stores buyer identifiers, and notifications for apps nobody has confirmed are dropped on arrival.
- To prove an app is yours, the Mac app sends a short-lived Google token about once a day; the server uses it for two Google API calls and never stores it.
- Your Mac pulls the notifications for your apps and looks up each purchase with your own Google sign-in, so order amounts never reach RevBell's server. The sale shows up in your notch, usually within 1–2 minutes. Sale details are part of RevBell Pro; the free plan tells you that a sale happened.
FAQ
Do notifications include the price?
No. They carry a purchase token; the amount comes from the Developer API (step 5).
Can several apps share one topic?
Yes. Each notification includes its packageName, so one topic and one receiver can serve all your apps.
Do I get one-time product purchases?
Only if you choose “Get all notifications for subscriptions and one-time products” in step 3.
How fast is it?
Google doesn't publish a delivery time for RTDN. Through RevBell's topic to a Mac, sale alerts usually arrive within 1–2 minutes.