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. Service account
Section titled “1. Service account”- In Google Cloud console pick a project and enable the Google Play Android Developer API.
- 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.
- 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.
- Permissions can take up to 24 hours to apply. Until then the API returns 401 or 403.
- Upload the key:
npx @kasskeep/cli apps update --id app_xxx --android-package com.example.app --google-service-account-file ./play-service-account.jsonThe 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.
2. Real-time developer notifications
Section titled “2. Real-time developer notifications”- In Google Cloud console, Pub/Sub → Create topic, for example
play-rtdn. - In the topic’s permissions, grant
[email protected]the Pub/Sub Publisher role. - 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.
- Delivery type Push, endpoint
- Tell Kasskeep the audience and email. RTDN returns 422 until both are set:
npx @kasskeep/cli apps update --id app_xxx \ --google-pubsub-audience https://api.kasskeep.com/v1/stores/google/app_xxx/rtdn \- In Play Console open your app, Monetize → Monetization setup → Real-time developer notifications, enter the full topic name
projects/<project>/topics/play-rtdnand send a test notification.
A topic can have several subscriptions, so another system can receive the same notifications through its own subscription.
How each push is checked
Section titled “How each push is checked”- The
Authorization: BearerOIDC token must be signed by Google, issued byaccounts.google.com, unexpired, withaudequal to the configured audience and a verifiedemailequal to the configured email. Otherwise 401. packageNamein the message must equal the app’sandroid_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.
Consumables
Section titled “Consumables”Kasskeep acknowledges or consumes every purchase after recording it. Tell it which one-time products are consumable; a trailing * matches a prefix:
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.
Products
Section titled “Products”- 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 asdata.base_plan_idanddata.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
linkedPurchaseTokenis merged into the existing subscription and keeps itsoriginal_transaction_id.
Client requirements
Section titled “Client requirements”- Play Billing Library 8 or later. Set
obfuscatedAccountIdto the user id. The SDK does this. - Submit the
purchaseTokento Kasskeep. Do not acknowledge or consume on the client.
Status mapping
Section titled “Status mapping”| 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.