Browse documentation

This guide connects one Android app to SubKit. When finished, the app can load Google Play products from a SubKit offering, verify purchases through the Play Developer API, and process subscription lifecycle changes through authenticated Real-time Developer Notifications (RTDN).

Trust boundary

  • The mobile app receives one public, app-bound SDK key (sk_sdk_…).
  • Google service-account keys remain encrypted in SubKit and never ship in the app.
  • App code does not select production or sandbox. Google provider evidence, including the server-side testPurchase marker, determines the environment.
  • RTDN is a change signal, not purchase authority. SubKit re-fetches the current purchase and order before changing access.
  • Google Play purchases are acknowledged only after SubKit accepts and persists the verified transaction.

Prerequisites

Before starting, make sure:

  • the app exists in Google Play Console with its final package name;
  • a signed Android App Bundle that includes Google Play Billing has been uploaded to at least one Play track;
  • a Google Payments profile is linked when the app sells paid products;
  • you can manage Google Cloud projects, service accounts, Pub/Sub, and Play Console permissions;
  • the Android app has the native IAP dependency described in Expo installation;
  • SubKit is reachable through public HTTPS for RTDN delivery.

Use a device-reachable HTTPS origin for local app testing. localhost on an Android device is the device itself, not your development machine.

Values you will need

Value Where to find it Used for
Android package name App build and Play Console Exact app and purchase verification scope
Developer API service-account email Google Cloud IAM Server access to catalog, purchases, and orders
Service-account JSON key Google Cloud IAM One-time encrypted upload to SubKit
Pub/Sub topic Google Cloud Pub/Sub Receiving RTDN from Google Play
Push service-account email Google Cloud IAM OIDC identity of the Pub/Sub push subscription
RTDN endpoint Your public SubKit origin https://<subkit-host>/api/stores/google/rtdn
Pub/Sub audience Push subscription settings Must exactly match the RTDN endpoint URL

Use two service accounts:

  1. a Developer API service account with a JSON key uploaded to SubKit;
  2. a Pub/Sub push identity with no key, used only to authenticate delivery to the RTDN endpoint.

1. Prepare the Google Play Developer API

  1. Choose or create a Google Cloud project for the Play integration.
  2. Enable the Google Play Developer API (Android Publisher API).
  3. Create a dedicated service account for SubKit.
  4. Do not grant broad project roles such as Owner or Editor.
  5. In Google Play Console, open Users and permissions and invite the service account email.
  6. Restrict access to the intended app where possible.
  7. Grant the Play permissions required for catalog and billing verification:
    • View app information and download bulk reports (read-only);
    • View financial data, orders, and cancellation survey responses;
    • Manage orders and subscriptions.
  8. Create and download a JSON key for this service account.

The JSON key is a server secret. Never put it in the mobile repository, app configuration, build profile, issue tracker, or logs.

Google permission changes can take time to propagate. If a newly created or updated credential still fails validation, re-check the project, JSON key, package access, and permissions, then allow up to 36 hours before treating the same configuration as invalid.

2. Create the Pub/Sub topic

  1. Enable the Cloud Pub/Sub API in the selected Google Cloud project.

  2. Create a topic, for example app-rtdn.

  3. Open the topic’s permissions.

  4. Add Google’s Play notification publisher:

    [email protected]
  5. Grant it Pub/Sub Publisher on this topic only.

This permission lets Google Play publish lifecycle signals. It does not grant access to SubKit or your Play Developer API credentials.

3. Create an authenticated push subscription

  1. Create a second service account to act as the push identity, for example subkit-rtdn-push.

  2. Do not create a JSON key for the push identity.

  3. Create a Pub/Sub push subscription for the RTDN topic.

  4. Set the push endpoint to:

    https://<subkit-host>/api/stores/google/rtdn
  5. Enable OIDC authentication and select the push service account.

  6. Set the audience to the exact same URL:

    https://<subkit-host>/api/stores/google/rtdn
  7. Ensure the Pub/Sub service agent can mint a token for the push identity. If authenticated delivery fails because token creation is denied, grant Service Account Token Creator on the push identity to:

    service-<project-number>@gcp-sa-pubsub.iam.gserviceaccount.com

The endpoint, audience, and configured push email must match exactly. SubKit rejects anonymous delivery and tokens issued for a different audience or service account.

4. Connect Google Play in SubKit

Google Play credentials are configured for the specific SubKit app.

  1. Open the app in the SubKit Console.
  2. Open App settings → Google Play.
  3. Enter the exact Android Package Name.
  4. Upload the Developer API service-account JSON key. SubKit extracts the service-account email and private key.
  5. Optional for financial reporting: enter the private Play reporting bucket ID (pubsite_prod_rev_*). The service account needs global View financial data permission; SubKit requests only the devstorage.read_only scope.
  6. Enter the exact RTDN URL in Pub/Sub Audience.
  7. Enter the keyless push identity in Pub/Sub Push E-Mail.
  8. Choose Connect Google Play or validate the existing connection.

SubKit validates Developer API access against the exact package before it stores the connection. A failed validation does not leave partially connected platform or integration records. A connected status and recent validation timestamp are the first success signals; they do not replace the purchase and RTDN tests below.

Do not reuse a credential from an unrelated Play project. Package name, Play Developer account, service-account permissions, and SubKit app must describe the same app.

5. Configure subscriptions and base plans in Play Console

  1. Open the app in Google Play Console.
  2. Under Monetize → Products → Subscriptions, create a subscription.
  3. Assign a stable Product ID, for example com.example.app.pro.
  4. Create one base plan for each purchasable term, for example:
    • monthly;
    • annual.
  5. For each base plan, configure:
    • auto-renewing or prepaid behavior;
    • billing period;
    • prices and regions;
    • grace period and account hold when required;
    • optional trials or offers.
  6. Activate the base plans.

Product ID and Base Plan ID are different identifiers. SubKit binds a plan version to the exact package name, Product ID, Base Plan ID, and optional Offer IDs.

Controlled catalog writes

SubKit never writes to Google Play automatically. Existing product listing metadata can be updated only through Preview → APPLY GOOGLE → Apply → Verify and only when SUBKIT_ENABLE_STORE_WRITES is enabled. Product IDs, package names, base-plan/purchase-option identities, billing periods, prices, states, offers, create and delete operations remain blocked in this conservative first scope. Products with multiple localized listings are also blocked rather than replacing all translations with one canonical name.

Financial report imports

Google Play financial exports are monthly ZIP/CSV objects in the private pubsite_prod_rev_* Cloud Storage bucket, not Android Publisher report endpoints. SubKit supports Estimated Sales and Earnings imports, handles UTF-16/UTF-8 CSV files, and persists only rows whose Package ID exactly matches the connected app. Imports are idempotent per app, report type and month. Reports usually appear 3–7 days after activity and never grant or revoke access.

6. Model the Google catalog in SubKit

  1. Create the entitlement the app checks, for example pro.
  2. Create the product and its plan.
  3. Create one immutable plan version per purchasable term with its prices, entitlement rules, and pool/capacity rules.
  4. Enable the Google sales channel.
  5. Add Google store bindings for both Production and Sandbox, including:
    • Android package name;
    • Google Product ID;
    • matching Base Plan ID;
    • allowed Offer IDs when applicable.
  6. Publish the plan versions.
  7. Add them to a published offering.
  8. In App settings, create or rotate the single public SDK key used by the app.
  9. Confirm the runtime offering contains the expected Google Product ID and Base Plan ID for every Android package.

The app must not contain static Google Product IDs, prices, or offer tokens. SubKit supplies the configured identifiers; the native billing adapter loads eligible offers and localized prices from Google Play.

See Catalog for the shared catalog model.

7. Enable RTDN in Play Console

  1. Open Monetize → Monetization setup.

  2. Enable Real-time developer notifications.

  3. Enter the full topic name:

    projects/<project-id>/topics/<topic-name>
  4. Select notification coverage that includes subscriptions and voided purchases. Include one-time product events if your catalog uses them.

  5. Save the configuration.

  6. Choose Send Test Message.

  7. Verify the complete path:

    • Play Console publishes successfully;
    • Pub/Sub performs an authenticated push;
    • SubKit returns HTTP 200;
    • SubKit records the test notification as an ignored Store Event without creating access.

A successful test publish proves delivery and authentication. It does not prove purchase verification; that requires a purchase from the app.

8. Configure Internal Testing and License Testing

  1. Upload a signed AAB to the Internal testing track.
  2. Publish the internal release.
  3. Add the test account to the track’s tester list.
  4. Add the same account under the account-wide License testing settings.
  5. Make the test track available in the tester’s country or region.
  6. Open the opt-in URL with that account. This step is mandatory; merely adding the email to the tester list does not opt the account in.
  7. Install or update the app through Google Play.
  8. Prefer a physical device. If you use an emulator, it must include the Google Play Store and Google Play services.
  9. Keep only the intended License Tester account active in the Play Store while diagnosing Sandbox account-selection problems. The purchasing account is normally the account that installed the app.
  10. Configure a screen lock/PIN if subscription checkout fails with a generic Play error.
  11. Before confirming checkout, verify:
  • the installed build is the intended Internal Testing release;
  • the purchasing account is the account that installed the app;
  • the checkout shows an accelerated test period;
  • a test payment instrument such as Test card, always approves is selected.
  1. Abort the checkout if it presents a real payment method.

A testing-track user is not automatically a License Tester. Without License Testing, purchases in a test track can charge real money. Use a non-License Tester only for a separately planned Production smoke test with an explicit cost and refund plan.

9. Verify the full flow

Run the purchase through the normal app UI:

  1. Identify an app user.
  2. Load the offering.
  3. Confirm each package has a native storeProduct, matching base plan, and localized Google Play price.
  4. Complete a purchase using the approved test instrument.
  5. Wait for SubKit to verify package, product, base plan, offer, account identity, purchase state, and order through the Developer API.
  6. Confirm the SDK acknowledges the purchase only after SubKit accepts it.
  7. Unlock only when the expected entitlement is active.
  8. Confirm the verified transaction, active entitlement, and recent Store Event appear in the SubKit Console before treating the test as successful.
  9. Restart the app and test Restore purchases.
  10. Confirm purchase and renewal RTDN update the same access source.
  11. Cancel renewal, wait for expiration, and confirm access is removed after the paid/test period ends.

License Tester subscriptions renew on accelerated schedules: approximately five minutes for weekly and monthly plans, ten minutes for three-month plans, 15 minutes for six-month plans, and 30 minutes for annual plans. Google limits test subscriptions to a small number of renewals, so use the provider state and RTDN evidence rather than assuming production timing.

Deleting an App User or local app data does not delete the underlying Google Play purchase. Use a fresh License Tester account or revoke/refund the previous purchase when you need a clean purchase history.

A successful purchase produces:

Verified Store Subscription
  → Access Source
  → Access Pool
  → Access Allocation
  → derived Entitlement Grant

The app checks the entitlement — never the Product ID, Base Plan ID, purchase token, or local billing callback.

Verification checklist

  • Play Developer API and Pub/Sub API are enabled in the intended project.
  • The Developer API service account has read-only app/catalog access plus the required financial and subscription-management permissions.
  • Its JSON key is uploaded only to SubKit and validates against the package.
  • The RTDN topic grants Google Play Publisher access.
  • The push subscription uses HTTPS, OIDC, and the exact audience.
  • SubKit is configured with the exact push service-account email.
  • Play Console’s test message reaches SubKit with HTTP 200.
  • The subscription and all intended base plans are active.
  • Production and Sandbox bindings contain package, Product ID, and Base Plan ID.
  • Plan versions and the offering are published.
  • The app contains only the public SubKit SDK key.
  • The installed build came from Google Play and checkout shows a test instrument.
  • The purchase is acknowledged only after SubKit verification.
  • RTDN retries, restore, cancellation, and expiration remain idempotent.

Failure modes

Symptom Check first
SubKit reports package permission denied Play Console invitation, read-only app/catalog permission, financial/subscription permissions, exact package, and up to 36-hour propagation
Subscription is absent from the app Active product/base plan, package, store binding, published plan version, and offering
Checkout shows a real payment method Installing/purchasing account, mandatory opt-in URL, test-country availability, and License Testing list
Play test message cannot publish Full topic name and Google Play publisher permission on the topic
Topic receives messages but endpoint does not Push URL, HTTPS certificate, OIDC settings, and Pub/Sub service-agent token permission
RTDN endpoint returns HTTP 400 Audience, issuer, verified push email, package name, and Pub/Sub envelope
Test purchase is refunded shortly after checkout Purchase was not acknowledged; fix the earlier SubKit verification failure
Purchase succeeds but entitlement stays inactive Product/base-plan/offer match, app-user identity, provider verification, and entitlement rule
The same lifecycle event appears more than once Pub/Sub is at-least-once; verify idempotency by message ID and provider evidence, not client state

Never disable RTDN authentication or acknowledge a purchase before verification to make a test pass. Correct the identity, credential, or catalog mismatch.

Type to search…

↑↓ navigate↵ selectEsc close