Skip to content

Google Play

Kasskeep verifies purchases with the Play Developer API, acknowledges and consumes them for you, and receives Real-time developer notifications (RTDN) through a Pub/Sub push subscription. Channel id: google_play, platform: android.

  1. In Google Cloud console pick a project and enable the Google Play Android Developer API.
  2. Under IAM & Admin → Service accounts, create a service account. It needs no Cloud roles. Under Keys → Add key, create a JSON key and download it.
  3. In Play Console open Users and permissions → Invite new users, enter the service account email, add your app under App permissions and grant:
    • View financial data, orders and cancellation survey responses;
    • Manage orders and subscriptions.
  4. Permissions can take up to 24 hours to apply. Until then the API returns 401 or 403.
  5. Upload the key:
Terminal window
npx @kasskeep/cli apps update --id app_xxx --android-package com.example.app --google-service-account-file ./play-service-account.json

The JSON must contain client_email and private_key. It is encrypted as a whole; GET .../credentials returns only the client email, project id and a private key fingerprint.

  1. In Google Cloud console, Pub/Sub → Create topic, for example play-rtdn.
  2. In the topic’s permissions, grant google-play-developer-notifications@system.gserviceaccount.com the Pub/Sub Publisher role.
  3. Create a subscription on the topic:
    • Delivery type Push, endpoint https://api.kasskeep.com/v1/stores/google/<app_id>/rtdn;
    • Enable authentication, pick a service account (its email is the Pub/Sub email below) and set an audience. Using the endpoint URL as the audience is simplest.
  4. Tell Kasskeep the audience and email. RTDN returns 422 until both are set:
Terminal window
npx @kasskeep/cli apps update --id app_xxx \
--google-pubsub-audience https://api.kasskeep.com/v1/stores/google/app_xxx/rtdn \
--google-pubsub-email pubsub-push@my-project.iam.gserviceaccount.com
  1. In Play Console open your app, Monetize → Monetization setup → Real-time developer notifications, enter the full topic name projects/<project>/topics/play-rtdn and send a test notification.

A topic can have several subscriptions, so another system can receive the same notifications through its own subscription.

  • The Authorization: Bearer OIDC token must be signed by Google, issued by accounts.google.com, unexpired, with aud equal to the configured audience and a verified email equal to the configured email. Otherwise 401.
  • packageName in the message must equal the app’s android_package. Otherwise 400.
  • Messages are deduplicated by messageId. The notification is treated as a signal only: Kasskeep always fetches the current state from the API before recording anything.
  • Success, duplicates and unknown tokens return 200. API failures return 502 and processing errors 500, so Pub/Sub redelivers.

Kasskeep acknowledges or consumes every purchase after recording it. Tell it which one-time products are consumable; a trailing * matches a prefix:

Terminal window
npx @kasskeep/cli apps update --id app_xxx --google-consumable-products "coins_*,gems_100"

Listed products are consumed, other one-time products are acknowledged as non-consumable. A consumable missing from the list is acknowledged instead and the user cannot buy it again. Passing the flag replaces the whole list; an empty string clears it.

Failed acknowledgements are retried in the background, starting after 1 minute and doubling up to every 2 hours. Google refunds purchases that are not acknowledged within 3 days, so a purchase whose acknowledgement keeps failing (usually missing Play permissions) needs your attention.

  • One-time products: the Play product id is the product_id. Enable pending purchases. Pending purchases are not recorded or acknowledged until they complete.
  • Subscriptions: the subscription id is the product_id. Base plans and offers are reported as data.base_plan_id and data.offer_id. Use separate subscription ids if access differs by period.
  • Only the first line item of a subscription purchase is read; add-on subscriptions are not supported.
  • Upgrades and downgrades: a new purchase with linkedPurchaseToken is merged into the existing subscription and keeps its original_transaction_id.
  • Play Billing Library 8 or later. Set obfuscatedAccountId to the user id. The SDK does this.
  • Submit the purchaseToken to Kasskeep. Do not acknowledge or consume on the client.
Google state status
SUBSCRIPTION_STATE_ACTIVE active, or canceled when auto-renew is off
SUBSCRIPTION_STATE_CANCELED canceled until expiry, then expired
SUBSCRIPTION_STATE_IN_GRACE_PERIOD grace_period
SUBSCRIPTION_STATE_ON_HOLD billing_retry
SUBSCRIPTION_STATE_PAUSED paused
SUBSCRIPTION_STATE_EXPIRED, SUBSCRIPTION_STATE_PENDING_PURCHASE_CANCELED expired
SUBSCRIPTION_STATE_PENDING Not recorded
Voided or SUBSCRIPTION_REVOKED revoked

Every hour Kasskeep also reads the Voided Purchases API (first run looks back 7 days, up to 30) and re-checks subscriptions that are close to expiry or in grace, hold or pause.