Google Play's billing system
is a service that
allows you to sell digital products and content in your Android app.
With the May 2022 release, we've changed how subscription products are
defined, and this affects how they are sold in-app and managed on your
backend. If you are integrating with Google Play Billing for the first
time, you can start your integration by reading
Getting ready
.
If you were selling subscriptions with Google Play Billing before May 2022,
it's important to understand how to adopt new features while maintaining
your existing subscriptions.
The first thing to know is that all of your existing subscriptions, apps,
and backend integrations function just as they did before the May 2022
release
. You don't need to make any immediate changes, and you can adopt
these new features over time. Each major release of the
Google Play Billing Library
is supported for two years after release. Existing integrations with the
Google Play Developer API
continue to function as before.
Here's an overview of the May 2022 updates:
- The new
Google Play Console
lets you create and manage subscriptions, base plans, and offers.
This includes both new and migrated subscriptions.
- The
Play Developer API
contains updates to support new Google Play Console UI functionality
in API form. Notably, there is a new version of the
Subscription Purchases API
.
Use this API to check subscription status and manage subscription purchases.
- The new
Play Billing Library version 5
allows your app to benefit from all the new subscription features.
When you're ready to upgrade to version 5, follow the guidance in the
migration guide
.
Subscriptions configuration
Managing subscriptions via Google Play Console
As of May 2022, you will notice some differences in the Google Play Console.
A single subscription can now have multiple base plans and
offers. Previously-created subscription SKUs now appear in
the Play Console as these new subscription, base plan, and
offer objects. If you haven't already, see
Recent changes to subscriptions in Play Console
for descriptions of the new objects, including their functionality and
configuration. All of your preexisting subscription products appear in the
Google Play Console in this new format. Each SKU is now represented by
a subscription object that contains a single base plan and backward-compatible
offer, if applicable.
Since older integrations expected each subscription to include a single offer,
represented by a
SkuDetails
object,
each subscription can have a single backward-compatible base plan or offer.
The backward-compatible base plan or offer is returned as part of a SKU
for apps that are using the now-deprecated
querySkuDetailsAsync()
method.
For more information on configuring and managing backward-compatible
offers, see
Understand subscriptions
Once your app is using only
queryProductDetailsAsync()
, and once there
are no older versions of your app still making purchases, you no longer
need to utilize a backward-compatible offer.
Managing subscriptions via Subscriptions Publishing API
The
Play Developer API
contains new functionality for subscription purchases. The
inappproducts
API for SKU management continues to work as before, including handling
one-time purchase products and subscriptions, so you don't need to
make any immediate changes to maintain your integration.
However, it's important to note that the Google Play Console uses only the new
subscription entities.
Once you start editing your subscriptions in the
Console, the
inappproducts
API can no longer be used for subscriptions
.
If you have used the Publishing API prior to May 2022, to avoid any issues,
any existing subscriptions now appear as read-only in the
Google Play Console. If you try to make changes, you may get a warning explaining
this limitation. Before further editing subscriptions in the Console,
you should update your backend integration to use the new Subscription
Publishing endpoints. The new
monetization.subscriptions
,
monetization.subscriptions.baseplans
,
and
monetization.subscriptions.offers
endpoints allow you to manage all available base plans and offers. You can see
how the different fields map from the
InAppProduct
entity to
the new objects under
monetization.subscriptions
in the following
table:
InAppProduct
|
Subscription
|
packageName
|
packageName
|
sku
|
productId
|
status
|
basePlans[0].state
|
prices
|
basePlans[0].regionalConfigs.price
|
listings
|
listings
|
defaultPrice
|
No equivalence
|
subscriptionPeriod
|
basePlans[0].autoRenewingBasePlanType.billingPeriodDuration
|
trialPeriod
|
basePlans[0].offers[0].phases[0].regionalConfigs[0].free
|
gracePeriod
|
basePlans[0].autoRenewingBasePlanType.gracePeriodDuration
|
subscriptionTaxesAndComplianceSettings
|
taxAndComplianceSettings
|
This required API update only applies to the Publishing API (SKU management).
Play Billing Library changes
To support gradual migration, the Play Billing Library includes all the
methods and objects available in previous versions.
SkuDetails
objects and functions like
querySkuDetailsAsync()
still exist so you can upgrade to use
new functionality
without having to also immediately update existing subscriptions code.
You can also control which offers are available through these methods
by marking them as backward-compatible.
In addition to keeping legacy methods, Play Billing Library 5 now includes
a new
ProductDetails
object and a corresponding
queryProductDetailsAsync()
method to handle new entities and functionality. Existing in-app products
(one-time purchases and consumables) are now also supported by
ProductDetails
.
For a subscription,
ProductDetails.getSubscriptionOfferDetails()
returns a list of all base plans and offers the user is eligible to purchase.
This means that you can access all base plans and offers eligible
for the user, regardless of backward-compatibility.
getSubscriptionOfferDetails()
returns
null
for non-subscription
products. For one-time purchases, you can use
getOneTimePurchaseOfferDetails()
.
Play Billing Library 5 also includes both new and legacy methods for
launching the purchase flow. If the
BillingFlowParams
object passed to
BillingClient.launchBillingFlow()
is configured using a
SkuDetails
object, the system extracts the offer
information to sell from the backward-compatible base plan or offer that
corresponds to the SKU. If the
BillingFlowParams
object passed to
BillingClient.launchBillingFlow()
is configured using
ProductDetailsParams
objects, which include
ProductDetails
and a
String
representing the specific offer token for the offer being
purchased, the system then uses that information to identify the
product being acquired by the user.
queryPurchasesAsync()
returns all purchases owned by
the user. To indicate the requested product type, you can pass
in a
BillingClient.SkuType
value, as in older versions, or a
QueryPurchasesParams
object that contains a
BillingClient.ProductType
value that represents the new subscription
entities.
We recommend
updating your apps
to version 5 of the library soon so you can start taking advantage
of these new subscription features.
Managing subscription status
This section describes the primary changes to the backend components of
a Google Play billing system integration that need to be implemented for
migration to version 5.
Real Time Developer Notifications
Soon the
SubscriptionNotification
object will no longer contain a
subscriptionId
. If you are relying on
this field to identify the subscription product, you should update
to obtain this information from the subscription status by using
purchases.subscriptionv2:get
once you receive the notification. Each
SubscriptionPurchaseLineItem
element
in the
lineItems
collection that is returned as part of the purchase status
will include the corresponding
productId
.
Subscriptions Purchases API: getting subscription status
In previous versions of the Subscriptions Purchases API, you could
query subscription status by using
purchases.subscriptions:get
.
This endpoint is unchanged and continues to work for backward-compatible
subscription purchases. This endpoint
does not
support any new
functionality released in May 2022.
In the new version of the Subscriptions Purchases API, use
purchases.subscriptionsv2:get
to obtain subscription purchase status. This API is compatible with
migrated subscriptions, new subscriptions (both prepaid and
auto-renewing), and purchases of all types. You can use this endpoint
to check for subscription status when receiving notifications. The
returned object,
SubscriptionPurchaseV2
, contains new fields,
but it still includes legacy data that is needed to continue supporting
existing subscriptions.
SubscriptionPurchaseV2 fields for prepaid plans
New fields have been added to support prepaid plans, which are extended by
the user instead of automatically renewing. All fields apply
to prepaid plans as they do for auto-renewing subscriptions,
with the following exceptions:
- [New field] lineItems[0].prepaid_plan.allowExtendAfterTime
: denotes
when a user will be allowed to buy another top-up to extend their prepaid
plan, as a user is allowed to have only one unconsumed top-up at a time.
- [New field] SubscriptionState
: specifies the subscription object state.
For prepaid plans, this value is always either
ACTIVE
,
PENDING
, or
CANCELED
.
- lineItems[0].expiryTime
: This field is always present for prepaid plans.
- paused_state_context
: This field is never present, as prepaid plans
cannot pause.
- lineItems[0].auto_renewing_plan
: Not present for prepaid plans.
- canceled_state_context
: Not present for prepaid plans, as this field
applies only to users who actively cancel a subscription.
- lineItems[0].productId
: This field replaces
subscriptionId
from
previous versions.
SubscriptionPurchaseV2 fields for recurring subscriptions
purchases.subscriptionv2
contains new fields that provide more detail
about new subscription objects. The following table shows how fields from
the legacy subscription endpoint map to corresponding fields in
purchases.subscriptionv2
.
SubscriptionPurchase
|
SubscriptionPurchaseV2
|
countryCode
|
regionCode
|
orderId
|
latestOrderId
|
(no equivalent field)
|
lineItems
(list of
SubscriptionPurchaseLineItem
)
that represents the products acquired with the purchase
|
(no equivalent field)
|
lineItems.offerDetails.basePlanId
|
(no equivalent field)
|
lineItems.offerDetails.offerId
|
(no equivalent field)
|
lineItems.offerDetails.offerTags
|
startTimeMillis
|
startTime
|
expiryTimeMillis
|
lineItems.expiryTime
(each subscription acquired
in the purchase has its own
expiryTime
)
|
(no equivalent field)
|
subscriptionState
(indicates the
state of the subscription
)
|
(no equivalent field)
|
pausedStateContext
(only present if the subscription
status is
SUBSCRIPTION_STATE_PAUSED
)
|
autoResumeTimeMillis
|
pausedStateContext.autoResumeTime
|
(no equivalent field)
|
canceledStateContext
(only present if the
subscription status is
SUBSCRIPTION_STATE_CANCELED
)
|
(no equivalent field)
|
testPurchase
(only present in licensed tester
purchases)
|
autoRenewing
|
lineItems.autoRenewingPlan.autoRenewEnabled
|
priceCurrenceCode
,
priceAmountMicros
,
introductoryPriceInfo
|
(no equivalent field)
This information can be found in the
basePlan
/
offer
for
each of the subscriptions purchased.
|
developerPayload
|
(no equivalent field) developer payload has been deprecated
|
paymentState
|
(no equivalent field)
You can infer the payment state from
subscriptionState
:
- Payment is pending:
SUBSCRIPTION_STATE_PENDING
(new purchases
with pending transaction)
SUBSCRIPTION_STATE_IN_GRACE_PERIOD
SUBSCRIPTION_STATE_ON_HOLD
- Payment has been received:
SUBSCRIPTION_STATE_ACTIVE
- Free trial:
- Deferred upgrade / downgrade:
SUBSCRIPTION_STATE_PENDING
|
cancelReason
,
userCancellationTimeMillis
,
cancelSurveyResult
|
canceledStateContext
|
linkedPurchaseToken
|
linkedPurchaseToken
(no change)
|
purchaseType
|
Test: through
testPurchase
Promotion: (no equivalent field); coming soon
|
priceChange
|
lineItems.autoRenewingPlan.priceChangeDetails
|
profileName
,
emailAddress
,
givenName
,
familyName
,
profileId
|
subscribeWithGoogleInfo
|
acknowledgementState
|
acknowledgementState (no change)
|
promotionType
,
promotionCode
|
(no equivalent field); coming soon
|
externalAccountId
,
obfuscatedExternalAccountId
,
obfuscatedExteranlProfileId
|
externalAccountIdentifiers
|
Other subscription management functions
While
purchases.subscriptions:get
has been upgraded to
purchases.subscriptionsv2:get
,
the rest of the developer subscription management functions remain
unchanged for now in the
purchases.subscriptions
endpoint,
so you can continue using
purchases.subscriptions:acknowledge
,
purchases.subscriptions:cancel
,
purchases.subscriptions:defer
,
purchases.subscriptions:refund
,
and
purchases.subscriptions:revoke
as you did before.
Pricing API
Use the
monetization.convertRegionPrices
endpoint to calculate regional prices as you would through the
Play Console. This method accepts a single price in any Play-supported
currency and returns converted prices (including the default rate of
tax where applicable) for all regions where Google Play supports purchases.