Integrate Tiered Subscriptions in Android Apps
Before updating your app's code, make sure to create in-app subscription items with separate SKUs. For instructions on how to set up the in-app items, see Set Up Tiered Subscriptions in Developer Console. Now you can use a modify subscription request to implement tiered subscriptions in your app.
Modify subscription request
The implementation process is similar to using the Appstore IAP (In-App Purchasing) purchase()
method. To review details about the purchase()
method, see PurchasingService.
When you call the purchase()
method, the Appstore SDK invokes the onPurchaseResponse()
callback. Similarly, when you call the modifySubscription()
method, the Appstore SDK invokes the onModifySubscriptionResponse()
callback.
The main differences between a purchase request and the modify subscription request are as follows:
- The
modifySubscription()
method takes aProrationMode
parameter and a SKU parameter in the request, while thepurchase()
method takes only SKU. TheProrationMode
parameter specifies when the plan modification takes effect. - The
ModifySubscriptionResponse
object uses a list of receipts, while thePurchaseResponse
object uses only one receipt.
The modifySubscription()
method identifies the current customer subscription and modifies it with the new term SKU. The SKU you pass in the modify subscription request is the term SKU that the customer is moving to. The ProrationMode
you pass in the request is an enum with the value of IMMEDIATE
or DEFERRED
, which specifies when the modification takes effect. The ModifySubscriptionResponse
object provides a list of receipts associated with the modification of the plan.
modifySubscription()
method.Modify subscription proration modes
You set the proration mode of a subscription with the ProrationMode
enum. This section describes the two possible values for ProrationMode
, which are IMMEDIATE
and DEFERRED
, in more detail.
Immediate proration mode
With ProrationMode
set to IMMEDIATE
, the customer's current subscription plan ends, and the new plan takes effect immediately. The customer gets a refund for the remaining period of the ended subscription, and is charged for the new subscription plan. The customer also receives an email specifying the refund amount for the old plan and the details of the new plan.
Since the current plan ends with prorated refund, and the new plan starts with a different order, the response contains two receipts:
- The last active receipt for the subscription, which contains cancellation date confirming the termination of the old subscription plan
- The new receipt for the newly changed plan
You must process both receipts to deliver immediately what the customer paid for.
Immediate response sample
In this example, a customer moves from term SkuX
to term SkuY
, effective immediately. The purchase happens on January 16. The original purchase of SkuX
happened on January 2. In this scenario, Amazon returns a message that contains the following:
receipts: [{
"receiptId": "oeUY1ip2mJWgLoOuGtAxndQS1LDJRGvmKLr6kq4u9G8=:3:11",
"sku": "baseSku",
"itemType": "SUBSCRIPTION",
"purchaseDate": "Thu Jan 16 09:25:25 GMT+05:30 2020",
"termSku": "SkuY"
}, {
"receiptId": "1bxFJrJVLPr8qpub8SijMWdAqXqWWGNUYPDpynoSusE=:3:11",
"sku": "baseSku",
"itemType": "SUBSCRIPTION",
"purchaseDate": "Thu Jan 02 12:41:44 GMT+05:30 2020",
"endDate": "Thu Jan 16 09:25:26 GMT+05:30 2020",
"termSku": "SkuX"
}]
Deferred proration mode
With ProrationMode
set to DEFERRED
, the subscription plan changes at the time of the upcoming renewal. The customer continues to have access to the current plan until renewal. The customer will be charged for the new plan at the time of renewal. The customer also receives an email with the deferred subscription details and the date of the upcoming modification.
Because the previous subscription plan remains active with no plan termination, the modify subscription response object only contains the active receipt. This receipt contains the deferred term SKU and the deferred date. You must use the data in the receipt to verify and deliver access to the new plan on the specified date. After the renewal, the same receipt ID will still be valid, but will be updated with the latest subscription details.
Deferred response sample
In this example, a customer moves from SkuA
to term SkuB
, effective at the time of renewal as specified in deferredDate
.
receipts: [{
"receiptId": "oeUY1ip2mJWgLoOuGtAxndQS1LDJRGvmKLr6kq4u9G9=:3:11",
"sku": "baseSku",
"itemType": "SUBSCRIPTION",
"purchaseDate": "Thu Jan 16 10:25:25 GMT+05:30 2020",
"deferredDate": "Thu Jan 23 10:25:26 GMT+05:30 2020",
"deferredSku": "SkuA",
"termSku": "SkuB"
}]
Implement modify subscription
The following code examples outline proper handling of the modify subscription requests and responses within your app.
Sample request
RequestId requestId = PurchasingService.modifySubscription("SKU", ProrationMode);
Sample response
An onModifySubscriptionResponse()
method handles responses from the modify subscription request. The method stores the status in a ModifySubscriptionResponse.RequestStatus
variable by using getRequestStatus()
. Based on the status, it either outputs receipts by using getReceipts()
, or handles errors.
@Override
public void onModifySubscriptionResponse(ModifySubscriptionResponse response) {
final String requestId = response.getRequestId().toString();
final String userId = response.getUserData().getUserId();
final ModifySubscriptionResponse.RequestStatus status = response.getRequestStatus();
Log.d(TAG, "onModifySubscriptionResponse: requestId (" + requestId
+ ") userId ("
+ userId
+ ") modifySubscriptionRequestStatus ("
+ status
+ ")");
Log.d(TAG, "ModifySubscriptionResponse " + response.toString());
switch (status) {
case SUCCESSFUL:
for(Receipt receipt : response.getReceipts()) {
Log.d(TAG, "onModifySubscriptionResponse: Receipt in json:" + receipt.toJSON());
iapManager.handleReceipt(response.getRequestId().toString(), receipt, response.getUserData());
}
break;
case INVALID_SKU:
Log.d(TAG,
"onModifySubscriptionResponse: Invalid SKU, onProductDataResponse should have already disabled the buy button.");
break;
case FAILED:
case NOT_SUPPORTED:
Log.d(TAG, "onModifySubscriptionResponse: Failed, so remove purchase request from local storage.");
iapManager.purchaseFailed(response.getRequestId().toString());
break;
}
}
Last updated: Apr 07, 2025