Subscriptions
Last updated
Last updated
Regular payments allow users to use the service for a fixed period, and payments are renewed regularly, in accordance with the payment cycle. In general, subscription services are used for music, movies, or games. Developers can configure multiple subscription products in one app to provide a variety of services, and users can use multiple subscriptions. Developers can also offer subscriptions at a discounted price or offer a free trial period to bring on new users. Similarly, you can convert products so that existing users can change the subscription products they are using.
When a user purchases a subscription product, it may go through various status changes while using the product. The app should check the status of the subscription and respond to each status change. The status of subscription can be checked using PurchaseClient.queryPurchasesAsync() in the ONE store IAP library or the server API getSubscriptionDetail.
A SubscriptionNotification is sent when the subscription status changes. For related information, see Using PNS (Push Notification Service).
When a user purchases a subscription, PurchaseClient.queryPurchasesAsync() returns the subscription result, and a SubscriptionNotification with SUBSCRIPTION_PURCHASED is sent. When you receive this notification, you must query the ONE store IAP API to update your subscription status. For subscription resources, see the following example.
A SUBSCRIPTION_RENEWED notification is sent when your subscription is renewed. When you receive this notification, you must query the ONE store IAP API to update the subscription status with the new expiration date. For subscription resources, see the following example.
For monthly auto-renewal products, payment will be made on the same day of the following month. The same works for 3-month and 6-month products. For example, if a subscription started on January 15th, the next payment will be made on February 15th. However, if there is no same date, the last day of the month will be the payment renewal date. For example, if a subscription started on January 31st, the next payment will be made on February 28th (or 29th), and the next payment will be made on March 28th (or 29th).
When a subscription expires, it will no longer be returned from PurchaseClient.queryPurchasesAsync() and the user will not be able to use the subscription. A SubscriptionNotification with SUBSCRIPTION_EXPIRED is also sent when the subscription expires. When you receive this notification, you must query the ONE store IAP API to update your subscription status. For subscription resources, see the following example.
Regular payment can be canceled directly by the user from the ONE store app. When there is a problem with the payment method, it can be canceled automatically if it is not resolved. You can also cancel subscriptions using the ONE store IAP API cancelRecurringPruchase. Even if the user directly cancels the subscription, the service must be available until the end of the current subscription period. If the subscription has been canceled but has not yet expired, it will be restored from PurchaseClient.queryPurchasesAsync(). A SUBSCRIPTION_CANCELED notification will be sent when your subscription is canceled. When you receive this notification, you must query the ONE store IAP API to update the status. When queried, autoRenewing=false and expiryTimeMillis are restored to when the user can use the service. If expiryTimeMillis is past the expiration date, the service will be stopped immediately, and if the expiration date is in the future, you can use the service until the date and time. For subscription resources, see the following example.
Users can cancel their subscriptions for a variety of reasons. If the subscription has been canceled, the service must be blocked immediately. In this case, PurchaseClient.queryPurchasesAsync() will no longer be restored, and the SUBSCRIPTION_REVOKED notification will be sent. When you receive this notification, you must query the ONE store IAP API to update the status. Subscription resources include autoRenewing and expiryTimeMillis. For subscription resources, see the following example.
If a user encounters a problem with their payment method while using the subscription and the problem is not resolved, the subscription will not be immediately terminated. In the above cases (1) Payment deferral - When a grace period is set (2) The subscription status is changed in the order of account pending. Whether to provide a payment grace period can be set in the ONE store Developer Center. If you set a grace period, users should be able to access subscription content during that period. If your app uses PurchaseClient.queryPurchasesAsync() to check subscription status, your app should handle the grace period automatically because PurchaseClient.queryPurchasesAsync() continues to return subscription status before the expiration date. When a user's subscription status becomes deferred payment, a notification is sent with SUBSCRIPTION_IN_GRACE_PERIOD . When you receive this notification, you must query the ONE store IAP API to update the status. Subscription resources include autoRenewing=true and expiryTimeMillis at a future point in time for grace to apply. If payment issues are not resolved within the grace period, the account will be placed on hold and users will not be able to access subscription content. Your app should display a message so the user can troubleshoot payment issues. You can provide deep links to help users resolve payment issues. As soon as the user resolves the payment issue, the subscription is renewed immediately.
If a user encounters an issue with their payment method while using a subscription and the issue is not resolved, the account will be placed on hold at the end of the grace period. The account hold period is up to 30 days, and unlike the grace period, subscription content is not available while the account is on hold. Also, subscriptions are not returned by PurchaseClient.queryPurchasesAsync() while on account hold. A SUBSCRIPTION_ON_HOLD notification is sent when a user's subscription is placed on account hold. When you receive this notification, you must update the subscription information by calling the ONE store IAP API. In account hold, the expiryTimeMillis of the subscription resource is set to the past. In the pending state, the user cannot access the subscription content, and the subscription is terminated after the specified holding period. So your app should display a message so the user can fix the problem. You can provide deep links to help users troubleshoot problems. If the user resolves the issue and the subscription is restored, the subscription date will change to the restored date. If the user does not resolve the issue before the end of the account hold period, a SUBSCRIPTION_CANCELED notification will be sent, and the subscription status should be updated by querying the ONE store IAP API.
Developers can enable the pause function in the ONE store Developer Center. By enabling the pause feature, users can pause their subscriptions for a period of time instead of canceling the app's subscription. The pause begins after the expiration of the current subscription product. Subscription content should not be available to users while suspended. At the end of the pause period, your subscription will resume. <Jonghwi Han - Description of picture pause 1 > Users can also resume subscriptions by manually unpausing before the end of the pause period. In this case, the subscription date will be the date on which the subscription is resumed by releasing the pause. It is not returned by PurchaseClient.queryPurchasesAsync() while paused. Returned by PurchaseClient.queryPurchasesAsync() when subscription resumes. When the user chooses to pause, a SubscriptionNotification of SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED is sent. At this point, the user has a subscription period remaining, and should therefore be able to continue to use subscription content. The subscription resource contains autoRenewing=true, paymentState=1 and future expiryTimeMillis, autoResumeTimeMillis values.
When a pause is initiated, a Subscription Notification with SUBSCRIPTION_PAUSED is sent. When the pause begins, the subscription period has expired, and the subscription content should not be available. The subscription resource contains autoRenewing=true, paymentState=0 and past values of expiryTimeMillis and autoResumeTimeMillis. A SubscriptionNotification with SUBSCRIPTION_RENEWED is sent when a subscription is automatically resumed at the end of the pause period, or when a user resumes a subscription by unpausing it. In this case, the same processing as Renew Subscription is required. If there is a billing problem when the subscription resumes, a subscription on hold occurs, which should be treated the same as a subscription on hold.
When a user changes a subscription product to another subscription product, the subscription in use is invalidated and a new subscription is created with a new purchase token. Subscription resources also contain a linkedPurchaseToken representing an existing subscription. "The inkedPurchaseToken allows you to look up previous subscriptions and associate new subscriptions with the same account. Now that a new subscription has been created, a Confirmation of Purchase for that payment is required. For subscription resources, see the following example.
ONE store provides a subscription management menu for users to easily manage subscription products. If PurchaseData is included in SubscriptionsParams as a parameter, the purchase data is checked and the management screen of the subscription product is executed. If SubscriptionParams is set to null, the user's subscription list screen is executed. The following is an example showing how to bring up the subscription management screen.
Users may want to change their plan to a better or cheaper subscription product while using a subscription. Users can change subscription products by paying for other subscription products, and developers can set up a prorated mode to handle changes to subscription products. The proration mode (PurchaseFlowParams.ProrationMode) that can be set is as follows.
The user is currently paying a monthly subscription for subscription product A. This regular payment is charged at 2,000 KRW and is renewed on the 1st of every month. On April 15th, the user decides to change the product to the annual subscription product B, which costs 36,000 KRW per year.
IMMEDIATE_WITH_TIME_PRORATION
Subscription product A ends immediately. The user paid for one month (April 1-30) and changed the product in the middle of the subscription period, so half of the monthly subscription fee (1,000 KRW) will be applied to the new subscription. However, the new subscription fee is 36,000 KRW per year, so your balance of 1,000 KRW is equivalent to 10 days (April 16-25). Therefore, you will be charged 36,000 KRW for the new subscription on April 26th, and 36,000 v will be charged on April 26th every year from the following year.
IMMEDIATE_AND_CHARGE_PRORATED_PRICE
You can use this mode because the price of subscription product B per hourly unit (36,000 KRW/year = KRW 3,000/month) is higher than the price of subscription product A (2,000 KRW/month). Subscription product A will end immediately. The user paid for the full month and only used half of the term, so half of the monthly subscription fee (1,000 KRW) will be applied to the new subscription. However, the new subscription fee is 36,000 KRW per year, so the fee for the remaining 15 days is 1,500 KRW. Therefore, the difference of 500 KRW will be charged as the new subscription fee. On May 1st, 36,000 KRW will be charged for the new subscription product B, and 36,000 KRW will be charged on May 1st of each year from the following year.
IMMEDIATE_WITHOUT_PRORATION
Subscription product A is immediately changed to subscription product B at no additional cost. And on May 1st, 36,000 KRW will be charged for the new subscription product B, and 36,000 KRW will be charged on May 1st every year from the following year.
DEFERRED
Subscription Plan A continues until it expires on April 30th. Subscription Product B goes into effect on May 1st, and users will be charged 36,000 KRW at the new subscription tier rate. Subscriptions can use the same API as "Request a Purchase" to provide users with the ability to change products. However, in order to change the product of the regular payment, the existing subscription purchase token and the pro-rata mode value are essential. You will need to provide information about the current subscription and the subscription and pro-rata mode that will be applied as a change, as in the following example.
The response is received by the PurchasesUpdatedListener because for the pro-rata mode, where the change is immediate, we do request a purchase logic. You can also receive a response upon request in View Purchase History. You must use PurchaseClient.acknowledgeAsync() or acknowledgePurchase to handle purchase confirmation. ONE store IAP API returns a linkedPurchaseToken from a subscription resource. You must invalidate the linkedPurchaseToken so that the old token is not used to gain access to the content. For prorated mode with deferred changes, you will receive a PurchasesUpdatedListener call with a subscription purchase and whether it has changed. Until the change takes effect, PurchaseClient.queryPurchasesAsync() continues to return purchase information from existing subscription information. When the change takes effect, PurchaseClient.queryPurchasesAsync() returns the purchase information for the new subscription product, and a Subscription Notification with SUBSCRIPTION_RENEWED is sent. We recommend that you receive this notification when a delayed change is made and use acknowledgePurchase to process the purchase confirmation.
With ONE store, if you are using a regular payment product to which a promotion is applied, you cannot change it to another product. However, the product subject to change can be changed even if promotion is applied. IMMEDIATE_WITH_TIME_PRORATION mode must be applied in order for users to continue to use the promotion of the product subject to change. In the case of other proportional distribution modes, the promotion cannot be applied even if the promotion is applied to the product subject to change.
You can use deferSubscription in the ONE store IAP API to defer the next payment date for a subscription user. During the deferral period, users will be able to access the content. Deferring the subscription deadline can be used in the following cases:
A special offer gives existing users access to an additional week of subscriptions.
An additional period of use may be granted to the user due to system failure, etc.
Payments can be deferred from a minimum of one day to a maximum of one year per API call. If you want to defer payment further, you can call the API again within the due date. When payment is delayed, you can send a notification via email or within the app to notify you that the payment date has changed.
You can change the price of subscription products in the ONE store Developer Center. If you change the base price of a subscription product, new purchases are immediately reflected at the changed price. However, in the case of users who are currently using a regular payment, a notification of the changed price will be sent after 7 days, and a period of consent for the price change will be provided for 30 days thereafter.
If the price of a Supscription Product that is planned to be changed into Deferred mode is changed, the flow of price change will start after the product is changed.
If you do not agree to the price change within the period, the subscription will be canceled on the next subscription date. (If the price goes down or remains, the changed price will be charged on the next renewal date after 7 days without a separate notification or consent process.)
If the user agrees to an increase in the subscription fee, or if the price is reduced, the price will be changed after the consent period. Also, a Subscription Notification is sent which is SUBSCRIPTION_PRICE_CHANGE_CONFIRMED.
If the user does not agree to an increase in the subscription fee, the subscription is automatically canceled and a Subscription Notification with SUBSCRIPTION_EXPIRED is sent.
If you accidentally change your subscription price, we recommend reverting to the original price. If you revert the price within 7 days, your existing subscription users will not be affected. However, even in this case, new users will pay at the changed price. Therefore, exercise caution when it comes to changing the price.
If the second price change is within 7 days of the first price change, the first price change will be void and only the second price change will take effect. However, after 7 days, the user must agree to two price changes. The consent process for price changes is inconvenient for users and increases the likelihood of fewer users maintaining the subscription product. Again, price changes should be made with caution.
PurchaseClient.queryPurchasesAsync()
getSubscriptionDetail
Status
Restored
recurringState
Restored
expiryTimeMillis
autoRenewing
Subscribed
Yes
0
Yes
Future
true
Canceled
Yes
1
Yes
Future
false
Grace period
Yes
0
Yes
Future - Expected expiry time or grade period ended (if any)
true
On hold
No
0
Yes
Ended
true
Temporarily paused
No
0
Yes
Ended
true
Expired
No
1
Yes
Ended
false
{+ "acknowledgementState": 0, // 새로운 정기결제를 구매한 경우에는 acknowledge가 필요합니다.+ "autoRenewing": true, "paymentState": 1, "lastPurchaseId": "22071114040010115614", "linkedPurchaseToken": null, "priceAmount": "610", "priceAmountMicros": 610000000, "nextPriceAmount": "610", "nextPriceAmountMicros": 610000000, "nextPaymentTimeMillis": 1658106000000, "pauseStartTimeMillis": null, "pauseEndTimeMillis": null, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657515841000,+ "expiryTimeMillis": 1658156399000, "autoResumeTimeMillis": null, "cancelledTimeMillis": null, "cancelReason": null, "promotionPrice": null, "priceChange": null}
{+ "acknowledgementState": 1,+ "autoRenewing": true, "paymentState": 1, "lastPurchaseId": "22071411443210116308", "linkedPurchaseToken": null, "priceAmount": "610", "priceAmountMicros": 610000000, "nextPriceAmount": "610", "nextPriceAmountMicros": 610000000, "nextPaymentTimeMillis": 1658365200000, "pauseStartTimeMillis": null, "pauseEndTimeMillis": null, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657766672000,+ "expiryTimeMillis": 1658501999000, "autoResumeTimeMillis": null, "cancelledTimeMillis": null, "cancelReason": null, "promotionPrice": null, "priceChange": null}
{ "acknowledgementState": 1,+ "autoRenewing": false, "paymentState": 1, "lastPurchaseId": "22071213191410115875", "linkedPurchaseToken": null, "priceAmount": "610", "priceAmountMicros": 610000000, "nextPriceAmount": "610", "nextPriceAmountMicros": 610000000, "nextPaymentTimeMillis": 1658192400000, "pauseStartTimeMillis": null, "pauseEndTimeMillis": null, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657599554000,+ "expiryTimeMillis": 1658242799000, "autoResumeTimeMillis": null, "cancelledTimeMillis": null, "cancelReason": null, "promotionPrice": null, "priceChange": null}
{ "acknowledgementState": 1,+ "autoRenewing": false, "paymentState": 1, "lastPurchaseId": "22071118111610115712", "linkedPurchaseToken": null, "priceAmount": "610", "priceAmountMicros": 610000000, "nextPriceAmount": "610", "nextPriceAmountMicros": 610000000, "nextPaymentTimeMillis": 1658106000000, "pauseStartTimeMillis": null, "pauseEndTimeMillis": null, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657515841000,+ "expiryTimeMillis": 1658156399000, "autoResumeTimeMillis": null,+ "cancelledTimeMillis": 1658156399000,+ "cancelReason": 1, "promotionPrice": null, "priceChange": null}
{ "acknowledgementState": 1,+ "autoRenewing": false, "paymentState": null, "lastPurchaseId": "22071216245010115987", "linkedPurchaseToken": null, "priceAmount": "610", "priceAmountMicros": 610000000, "nextPriceAmount": "610", "nextPriceAmountMicros": 610000000, "nextPaymentTimeMillis": 1658192400000, "pauseStartTimeMillis": null, "pauseEndTimeMillis": null, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657610690000,+ "expiryTimeMillis": 1657610749000, "autoResumeTimeMillis": null,+ "cancelledTimeMillis": 1657610749000,+ "cancelReason": 1, "promotionPrice": null, "priceChange": null}
{ "acknowledgementState": 0,+ "autoRenewing": true, "paymentState": 0, "lastPurchaseId": "22071209533410115807", "linkedPurchaseToken": null, "priceAmount": "610", "priceAmountMicros": 610000000, "nextPriceAmount": "610", "nextPriceAmountMicros": 610000000, "nextPaymentTimeMillis": 1658192400000, "pauseStartTimeMillis": null, "pauseEndTimeMillis": null, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657587215000,+ "expiryTimeMillis": 1658242799000, "autoResumeTimeMillis": null, "cancelledTimeMillis": null, "cancelReason": null, "promotionPrice": null, "priceChange": null}
{ "acknowledgementState": 0,+ "autoRenewing": true, "paymentState": 0, "lastPurchaseId": "22071209361310115799", "linkedPurchaseToken": null, "priceAmount": "610", "priceAmountMicros": 610000000, "nextPriceAmount": "610", "nextPriceAmountMicros": 610000000, "nextPaymentTimeMillis": 1659315600000, "pauseStartTimeMillis": null, "pauseEndTimeMillis": null, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657586174000,+ "expiryTimeMillis": 1658242799000, "autoResumeTimeMillis": null, "cancelledTimeMillis": null, "cancelReason": null, "promotionPrice": null, "priceChange": null}
{ "acknowledgementState": 1,+ "autoRenewing": true,+ "paymentState": 1, "lastPurchaseId": "22071114040010115614", "linkedPurchaseToken": null, "priceAmount": "610", "priceAmountMicros": 610000000, "nextPriceAmount": "610", "nextPriceAmountMicros": 610000000, "nextPaymentTimeMillis": 1660698000000,+ "pauseStartTimeMillis": 1660748400000,+ "pauseEndTimeMillis": 1663340399000, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657515841000,+ "expiryTimeMillis": 1660748399000,+ "autoResumeTimeMillis": 1660698000000, "cancelledTimeMillis": null, "cancelReason": null, "promotionPrice": null, "priceChange": null}
{ "acknowledgementState": 1,+ "autoRenewing": true,+ "paymentState": 0, "lastPurchaseId": "22071114040010115614", "linkedPurchaseToken": null, "priceAmount": "610", "priceAmountMicros": 610000000, "nextPriceAmount": "610", "nextPriceAmountMicros": 610000000, "nextPaymentTimeMillis": 1663290000000,+ "pauseStartTimeMillis": 1660748400000,+ "pauseEndTimeMillis": 1663340399000, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657515841000,+ "expiryTimeMillis": 1660748399000,+ "autoResumeTimeMillis": 1663290000000, "cancelledTimeMillis": null, "cancelReason": null, "promotionPrice": null, "priceChange": null}
{ "acknowledgementState": 1, "autoRenewing": true, "paymentState": 1, "lastPurchaseId": "22071214572510115940",+ "linkedPurchaseToken": "220712131914S0115875", "priceAmount": "600", "priceAmountMicros": 600000000, "nextPriceAmount": "600", "nextPriceAmountMicros": 600000000, "nextPaymentTimeMillis": 1660266000000, "pauseStartTimeMillis": null, "pauseEndTimeMillis": null, "priceCurrencyCode": "KRW", "countryCode": "KR", "startTimeMillis": 1657605449000, "expiryTimeMillis": 1660316399000, "autoResumeTimeMillis": null, "cancelledTimeMillis": null, "cancelReason": null, "promotionPrice": null, "priceChange": null}
Standard Uri
Standard parameter
caller_package (mandatory)
packageName of the app to call the integration specification
purchase_token (optional)
purchase Token to go to specific purchase details
Details
Go to My Page > Subscriptions List screen.
If purchase_token exists, go to the subscription details of the purchase token.
Supported version
ONE store Client v7.9.0 and higher ( android:versionName="7.9.0" android:versionCode="70900" ) ONE store Service v7.140 and higher
Prorated Mode
Description