CINXE.COM

Sell subscriptions  |  Google Play's billing system  |  Android Developers

<!doctype html> <html lang="en" dir="ltr"> <head><script type="text/javascript" src="/_static/js/bundle-playback.js?v=HxkREWBo" charset="utf-8"></script> <script type="text/javascript" src="/_static/js/wombat.js?v=txqj7nKC" charset="utf-8"></script> <script>window.RufflePlayer=window.RufflePlayer||{};window.RufflePlayer.config={"autoplay":"on","unmuteOverlay":"hidden"};</script> <script type="text/javascript" src="/_static/js/ruffle/ruffle.js"></script> <script type="text/javascript"> __wm.init("https://web.archive.org/web"); __wm.wombat("https://developer.android.com/google/play/billing/subscriptions","20210507003611","https://web.archive.org/","web","/_static/", "1620347771"); </script> <link rel="stylesheet" type="text/css" href="/_static/css/banner-styles.css?v=S1zqJCYt" /> <link rel="stylesheet" type="text/css" href="/_static/css/iconochive.css?v=3PDvdIFv" /> <!-- End Wayback Rewrite JS Include --> <meta name="google-signin-client-id" content="721724668570-nbkv1cfusk7kk4eni4pjvepaus73b13t.apps.googleusercontent.com"> <meta name="google-signin-scope" content="profile email https://www.googleapis.com/auth/developerprofiles https://www.googleapis.com/auth/developerprofiles.award"> <meta property="og:site_name" content="Android Developers"> <meta property="og:type" content="website"> <meta name="theme-color" content="#3ddc84"> <meta charset="utf-8"> <meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="manifest" href="/web/20210507003611/https://developer.android.com/_pwa/android/manifest.json" crossorigin="use-credentials"> <link rel="preconnect" href="//web.archive.org/web/20210507003611/https://www.gstatic.com/" crossorigin> <link rel="preconnect" href="//web.archive.org/web/20210507003611/https://fonts.gstatic.com/" crossorigin> <link rel="preconnect" href="//web.archive.org/web/20210507003611/https://fonts.googleapis.com/" crossorigin> <link rel="preconnect" href="//web.archive.org/web/20210507003611/https://apis.google.com/" crossorigin> <link rel="preconnect" href="//web.archive.org/web/20210507003611/https://www.google-analytics.com/" crossorigin> <link rel="stylesheet" href="//web.archive.org/web/20210507003611cs_/https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700|Material+Icons"> <link rel="stylesheet" href="https://web.archive.org/web/20210507003611cs_/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android/css/rebrand-app.css"> <link rel="shortcut icon" href="https://web.archive.org/web/20210507003611im_/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android/images/favicon.png"> <link rel="apple-touch-icon" href="https://web.archive.org/web/20210507003611im_/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android/images/touchicon-180.png"><link rel="canonical" href="https://web.archive.org/web/20210507003611/https://developer.android.com/google/play/billing/subscriptions"><link rel="search" type="application/opensearchdescription+xml" title="Android Developers" href="https://web.archive.org/web/20210507003611/https://developer.android.com/s/opensearch.xml"> <title>Sell subscriptions &nbsp;|&nbsp; Google Play's billing system &nbsp;|&nbsp; Android Developers</title> <meta property="og:title" content="Sell subscriptions  |  Google Play's billing system  |  Android Developers"> <meta property="og:url" content="https://web.archive.org/web/20210507003611/https://developer.android.com/google/play/billing/subscriptions"> <meta property="og:image" content="https://web.archive.org/web/20210507003611im_/https://developer.android.com/images/social/android-developers.png"> <meta property="og:image:width" content="1200"> <meta property="og:image:height" content="675"> <meta property="og:locale" content="en"> <meta name="twitter:card" content="summary_large_image"> </head> <body class="" template="page" theme="android-theme" type="article" layout="docs" pending> <devsite-progress type="indeterminate" id="app-progress"></devsite-progress> <section class="devsite-wrapper"><devsite-header> <div class="devsite-header--inner nocontent"> <div class="devsite-top-logo-row-wrapper-wrapper"> <div class="devsite-top-logo-row-wrapper"> <div class="devsite-top-logo-row"> <button type="button" id="devsite-hamburger-menu" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Navigation menu button" visually-hidden aria-label="Open menu"> </button> <div class="devsite-product-name-wrapper"> <a href="/web/20210507003611/https://developer.android.com/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="androidDevelopers" track-metadata-position="nav" track-metadata-eventdetail="nav"> <img src="https://web.archive.org/web/20210507003611im_/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android/images/lockup.svg" class="devsite-site-logo" alt="Android Developers"> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list"> <li class="devsite-breadcrumb-item devsite-has-google-wordmark"> </li> </ul> </span> </div> <div class="devsite-top-logo-row-middle"> <div class="devsite-header-upper-tabs"> <devsite-tabs class="upper-tabs"> <nav class="devsite-tabs-wrapper" aria-label="Upper tabs"> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/about" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="platform" data-category="Site-Wide Custom Events" data-label="Tab: Platform"> Platform </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/studio" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="androidStudio" data-category="Site-Wide Custom Events" data-label="Tab: Android Studio"> Android Studio </a> </tab> <tab active> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="googlePlay" aria-label="Google Play, selected" data-category="Site-Wide Custom Events" data-label="Tab: Google Play"> Google Play </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/jetpack" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="jetpack" data-category="Site-Wide Custom Events" data-label="Tab: Jetpack"> Jetpack </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/kotlin" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="kotlin" data-category="Site-Wide Custom Events" data-label="Tab: Kotlin"> Kotlin </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/docs" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="docs" data-category="Site-Wide Custom Events" data-label="Tab: Docs"> Docs </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/news" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="news" data-category="Site-Wide Custom Events" data-label="Tab: News"> News </a> </tab> </nav> </devsite-tabs> </div> <devsite-search aria-expanded="false" aria-haspopup="listbox" enable-signin enable-search enable-suggestions enable-query-completion project-name="Google Play's billing system" tenant-name="Android Developers" role="combobox"> <form class="devsite-search-form" action="https://web.archive.org/web/20210507003611/https://developer.android.com/s/results" method="GET"> <div class="devsite-search-container"> <div class="devsite-searchbox"> <input aria-activedescendant="" aria-autocomplete="list" aria-label="Search" aria-haspopup="false" aria-multiline="false" aria-label="Search box" autocomplete="off" class="devsite-search-field devsite-search-query" name="q" placeholder="Search" role="combobox" type="text" value=""> <div class="devsite-search-image material-icons" aria-hidden="true"></div> </div> <button type="button" search-open class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Open search"></button> </div> </form> <button type="button" search-close class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Close search"></button> </devsite-search> </div> <devsite-language-selector> <devsite-select class="devsite-language-selector-menu"> <select aria-label="Select your language preference." class="devsite-language-selector-select" name="language" track-name="click" track-type="languageSelector"> <option>Language</option> <option value="en" lang="en" track-metadata-original-language="en" track-metadata-selected-language="en" track-name="changed" track-type="languageSelector"> English </option> <option value="id" lang="id" track-metadata-original-language="en" track-metadata-selected-language="id" track-name="changed" track-type="languageSelector"> Bahasa Indonesia </option> <option value="es_419" lang="es_419" track-metadata-original-language="en" track-metadata-selected-language="es_419" track-name="changed" track-type="languageSelector"> Español – América Latina </option> <option value="pt_br" lang="pt_br" track-metadata-original-language="en" track-metadata-selected-language="pt_br" track-name="changed" track-type="languageSelector"> Português – Brasil </option> <option value="zh_cn" lang="zh_cn" track-metadata-original-language="en" track-metadata-selected-language="zh_cn" track-name="changed" track-type="languageSelector"> 中文 – 简体 </option> <option value="ja" lang="ja" track-metadata-original-language="en" track-metadata-selected-language="ja" track-name="changed" track-type="languageSelector"> 日本語 </option> <option value="ko" lang="ko" track-metadata-original-language="en" track-metadata-selected-language="ko" track-name="changed" track-type="languageSelector"> 한국어 </option> </select> </devsite-select> </devsite-language-selector> <devsite-user enable-profiles id="devsite-user"></devsite-user> </div> </div> </div> <div class="devsite-collapsible-section "> <div class="devsite-header-background"> <div class="devsite-product-id-row"> <div class="devsite-product-description-row"> <ul class="devsite-breadcrumb-list"> <li class="devsite-breadcrumb-item "> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Lower Header" data-value="1" track-type="globalNav" track-name="breadcrumb" track-metadata-position="1" track-metadata-eventdetail=""> Google Play </a> </li> </ul> </div> </div> <div class="devsite-doc-set-nav-row"> <devsite-tabs class="lower-tabs"> <nav class="devsite-tabs-wrapper" aria-label="Lower tabs"> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="overview" data-category="Site-Wide Custom Events" data-label="Tab: Overview"> Overview </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute/console" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="playConsole" data-category="Site-Wide Custom Events" data-label="Tab: Play Console"> Play Console </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute/google-play" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="playStore" data-category="Site-Wide Custom Events" data-label="Tab: Play Store"> Play Store </a> </tab> <tab active> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/google/play/billing" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="playBilling" aria-label="Play Billing, selected" data-category="Site-Wide Custom Events" data-label="Tab: Play Billing"> Play Billing </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute/play-policies" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="playPolicies" data-category="Site-Wide Custom Events" data-label="Tab: Play Policies"> Play Policies </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute/play-services" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="playServices" data-category="Site-Wide Custom Events" data-label="Tab: Play Services"> Play Services </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute/games" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="games" data-category="Site-Wide Custom Events" data-label="Tab: Games"> Games </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute/best-practices" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="guides" data-category="Site-Wide Custom Events" data-label="Tab: Guides"> Guides </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute/marketing-tools" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="resources" data-category="Site-Wide Custom Events" data-label="Tab: Resources"> Resources </a> </tab> <tab> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/stories" class="gc-analytics-event " track-type="globalNav" track-metadata-position="nav" track-metadata-eventdetail="nav" track-name="stories" data-category="Site-Wide Custom Events" data-label="Tab: Stories"> Stories </a> </tab> </nav> </devsite-tabs> </div> </div> </div> </div> </devsite-header> <devsite-book-nav scrollbars> <nav class="devsite-book-nav devsite-nav nocontent" aria-label="Side menu"> <div class="devsite-mobile-header"> <button type="button" id="devsite-close-nav" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Close navigation" aria-label="Close navigation"> </button> <div class="devsite-product-name-wrapper"> <a href="/web/20210507003611/https://developer.android.com/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="androidDevelopers" track-metadata-position="nav" track-metadata-eventdetail="nav"> <img src="https://web.archive.org/web/20210507003611im_/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android/images/lockup.svg" class="devsite-site-logo" alt="Android Developers"> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list"> <li class="devsite-breadcrumb-item devsite-has-google-wordmark"> </li> </ul> </span> </div> </div> <div class="devsite-book-nav-wrapper"> <div class="devsite-mobile-nav-top"> <ul class="devsite-nav-list"> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/about" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Platform" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="platform"> <span class="devsite-nav-text" tooltip> Platform </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/studio" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Android Studio" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="androidStudio"> <span class="devsite-nav-text" tooltip> Android Studio </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/distribute" class="devsite-nav-title gc-analytics-event devsite-nav-active" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google Play" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="googlePlay"> <span class="devsite-nav-text" tooltip> Google Play </span> </a> <ul class="devsite-nav-responsive-tabs"> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/distribute" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Overview" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="overview"> <span class="devsite-nav-text" tooltip> Overview </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/distribute/console" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Play Console" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="playConsole"> <span class="devsite-nav-text" tooltip> Play Console </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/distribute/google-play" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Play Store" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="playStore"> <span class="devsite-nav-text" tooltip> Play Store </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/google/play/billing" class="devsite-nav-title gc-analytics-event devsite-nav-has-children devsite-nav-active" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Play Billing" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="playBilling"> <span class="devsite-nav-text" tooltip menu="_book"> Play Billing </span> <span class="devsite-nav-icon material-icons" data-icon="forward" menu="_book"> </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/distribute/play-policies" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Play Policies" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="playPolicies"> <span class="devsite-nav-text" tooltip> Play Policies </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/distribute/play-services" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Play Services" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="playServices"> <span class="devsite-nav-text" tooltip> Play Services </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/distribute/games" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Games" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="games"> <span class="devsite-nav-text" tooltip> Games </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/distribute/best-practices" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Guides" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="guides"> <span class="devsite-nav-text" tooltip> Guides </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/distribute/marketing-tools" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Resources" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="resources"> <span class="devsite-nav-text" tooltip> Resources </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/stories" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Stories" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="stories"> <span class="devsite-nav-text" tooltip> Stories </span> </a> </li> </ul> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/jetpack" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Jetpack" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="jetpack"> <span class="devsite-nav-text" tooltip> Jetpack </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/kotlin" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Kotlin" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="kotlin"> <span class="devsite-nav-text" tooltip> Kotlin </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/docs" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Docs" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="docs"> <span class="devsite-nav-text" tooltip> Docs </span> </a> </li> <li class="devsite-nav-item"> <a href="/web/20210507003611/https://developer.android.com/news" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: News" track-type="globalNav" track-metadata-eventdetail="globalMenu" track-metadata-position="nav" track-name="news"> <span class="devsite-nav-text" tooltip> News </span> </a> </li> </ul> </div> <div class="devsite-mobile-nav-bottom" role="navigation"> <ul class="devsite-nav-list" menu="_book"> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"><span class="devsite-nav-text" tooltip>Google Play&#39;s billing system</span></div></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Overview</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/terminology" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Terminology</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/getting-ready" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Getting ready</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Integrate the library</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/subscriptions" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Sell subscriptions</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/promo" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Offer a promotion</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/test" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Test your integration</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/release-notes" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Library release notes</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/contact" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Contact us</span></a></li> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"><span class="devsite-nav-text" tooltip>Additional guides</span></div></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/security" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Fight fraud and abuse</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/migrate" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Migrate from AIDL</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/developer-payload" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Developer payload</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/unity" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Use the Billing Library with Unity</span></a></li> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"><span class="devsite-nav-text" tooltip>Resources</span></div></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/classes" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Play Billing Library reference</span></a></li> <li class="devsite-nav-item"><a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Google Play Developer API</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/additional-resources" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Additional resources</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/rtdn-reference" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Real-time developer notifications reference</span></a></li> <li class="devsite-nav-item devsite-nav-heading"><div class="devsite-nav-title devsite-nav-title-no-path"><span class="devsite-nav-text" tooltip>Deprecated content</span></div></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/billing_reference" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>AIDL reference</span></a></li> <li class="devsite-nav-item"><a href="/web/20210507003611/https://developer.android.com/google/play/billing/billing_rewarded_products" class="devsite-nav-title"><span class="devsite-nav-text" tooltip>Rewarded products</span></a></li> </ul> </div> </div> </nav> </devsite-book-nav> <section id="gc-wrapper"> <main role="main" class="devsite-main-content" has-book-nav has-toc> <devsite-toc class="devsite-nav"></devsite-toc> <devsite-content> <article class="devsite-article"> <div class="devsite-banner devsite-banner-announcement"> <div class="devsite-banner-message"> <div class="devsite-banner-message-text"> <b>Reminder:</b> Starting on August 2, 2021, all new apps must use Billing Library version 3 or newer. By November 1, 2021, all updates to existing apps must use Billing Library version 3 or newer. <a href="https://web.archive.org/web/20210507003611/https://android-developers.googleblog.com/2020/06/meet-google-play-billing-library.html"> Learn more</a>. </div> </div> </div> <div class="devsite-article-meta" role="navigation"> <ul class="devsite-breadcrumb-list" aria-label="Breadcrumb"> <li class="devsite-breadcrumb-item "> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="1" track-type="globalNav" track-name="breadcrumb" track-metadata-position="1" track-metadata-eventdetail="Google Play's billing system"> Google Play&#39;s billing system </a> </li> <li class="devsite-breadcrumb-item "> <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/distribute" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="2" track-type="globalNav" track-name="breadcrumb" track-metadata-position="2" track-metadata-eventdetail=""> Google Play </a> </li> <li class="devsite-breadcrumb-item "> <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> <a href="https://web.archive.org/web/20210507003611/https://developer.android.com/google/play/billing" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="3" track-type="globalNav" track-name="breadcrumb" track-metadata-position="3" track-metadata-eventdetail=""> Play Billing </a> </li> </ul> <devsite-thumb-rating position="header"> <template class="thumb-down-categories"> [{ "type": "thumb-down", "id": "missingTheInformationINeed", "label":"Missing the information I need" },{ "type": "thumb-down", "id": "tooComplicatedTooManySteps", "label":"Too complicated / too many steps" },{ "type": "thumb-down", "id": "outOfDate", "label":"Out of date" },{ "type": "thumb-down", "id": "samplesCodeIssue", "label":"Samples/Code issue" },{ "type": "thumb-down", "id": "otherDown", "label":"Other" }] </template> <template class="thumb-up-categories"> [{ "type": "thumb-up", "id": "easyToUnderstand", "label":"Easy to understand" },{ "type": "thumb-up", "id": "solvedMyProblem", "label":"Solved my problem" },{ "type": "thumb-up", "id": "otherUp", "label":"Other" }] </template> </devsite-thumb-rating> </div> <h1 class="devsite-page-title">Sell subscriptions<devsite-bookmark></devsite-bookmark></h1> <devsite-toc class="devsite-nav" devsite-toc-embedded> </devsite-toc> <div class="devsite-article-body clearfix "> <p>This topic describes how to handle subscription lifecycle events, such as renewals and expirations. It also describes additional subscription features such as offering promotions and allowing your users to manage their own subscriptions.</p> <p>Before reading this topic, be sure you&#39;ve read <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate">Integrate the Google Play Billing Library into your app</a> for general instructions on how to sell and manage products in your app.</p> <p>If you haven&#39;t configured subscription products for your app, see <a href="/web/20210507003611/https://developer.android.com/google/play/billing/getting-ready#products">Create and configure your products</a>.</p> <h2 id="lifecycle" data-text="Handling the subscription lifecycle">Handling the subscription lifecycle</h2> <p>A subscription can go through various state changes throughout its <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate#life">lifecycle</a>, and your app needs to respond to each change. To check the subscriber&#39;s state, your app can query using either <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">BillingClient.queryPurchases()</code></a> in the Google Play Billing Library or <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/get"><code translate="no" dir="ltr">Purchases.subscriptions:get</code></a> in the Google Play Developer API.</p> <table> <tr> <td></td> <td colspan="2" style="background-color:#f1f3f4;border-left:solid black thin;border-right:solid black thin"><strong> <code translate="no" dir="ltr">BillingClient.queryPurchases()</code></strong></td> <td colspan="4"><strong> <code translate="no" dir="ltr">Purchases.subscriptions:get</code></strong></td> </tr> <tr style="border-bottom:solid black thin"> <td><strong>State</strong></td> <td style="background-color:#f1f3f4;border-left:solid black thin"><strong>Is returned?</strong></td> <td style="background-color:#f1f3f4;border-right:solid black thin"><strong> <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/Purchase#isautorenewing">isAutoRenewing</a> </strong></td> <td><strong>Is returned?</strong></td> <td><strong>expiryTimeMillis</strong></td> <td><strong>paymentState</strong></td> <td><strong>autoRenewing</strong></td> </tr> <tr> <td><strong>Active</strong></td> <td style="background-color:#f1f3f4;border-left:solid black thin">Yes</td> <td style="background-color:#f1f3f4;border-right:solid black thin">True</td> <td>Yes</td> <td>Future</td> <td>1 (Payment Received)</td> <td>True</td> </tr> <tr> <td><strong>Cancelled</strong></td> <td style="background-color:#f1f3f4;border-left:solid black thin">Yes</td> <td style="background-color:#f1f3f4;border-right:solid black thin">False</td> <td>Yes</td> <td>Future</td> <td>1 (Payment Received)</td> <td>False</td> </tr> <tr> <td><strong>In grace period</strong></td> <td style="background-color:#f1f3f4;border-left:solid black thin">Yes</td> <td style="background-color:#f1f3f4;border-right:solid black thin">True</td> <td>Yes</td> <td>Future</td> <td>0 (Payment Pending)</td> <td>True</td> </tr> <tr> <td><strong>On hold</strong></td> <td style="background-color:#f1f3f4;border-left:solid black thin">No</td> <td style="background-color:#f1f3f4;border-right:solid black thin">N/A</td> <td>Yes</td> <td>Past</td> <td>0 (Payment Pending)</td> <td>True</td> </tr> <tr> <td><strong>Paused</strong></td> <td style="background-color:#f1f3f4;border-left:solid black thin">No</td> <td style="background-color:#f1f3f4;border-right:solid black thin">N/A</td> <td>Yes</td> <td>Past</td> <td>1 (Payment Received)</td> <td>True</td> </tr> <tr> <td><strong>Expired</strong></td> <td style="background-color:#f1f3f4;border-left:solid black thin">No</td> <td style="background-color:#f1f3f4;border-right:solid black thin">N/A</td> <td>Yes</td> <td>Past</td> <td>1 (Payment Received)</td> <td>False</td> </tr> </table> <aside class="note"><strong>Note:</strong><span> The purchase token is valid from subscription signup until 60 days after expiration. After this date, the purchase token is no longer valid to call the Google Play Developer API.</span></aside> <p>If your app stores subscription state on a secure backend server, your app should listen for state changes using <a href="/web/20210507003611/https://developer.android.com/google/play/billing/getting-ready#configure-rtdn">Real-time developer notifications</a> to ensure state is kept in-sync. A <a href="/web/20210507003611/https://developer.android.com/google/play/billing/rtdn-reference#sub"><code translate="no" dir="ltr">SubscriptionNotification</code></a> is sent for events affecting subscription state such as renewals and cancellations. You need to call the developer API after receiving a Real-time developer notifications to get the complete status and update your own backend state. These notifications tell you only that the subscription state changed. They do not give you complete information about overall subscription status.</p> <aside class="note"><strong>Note:</strong><span> Due to quota restrictions, it is not recommended to check state by polling the Google Play Developer API at regular intervals instead of leveraging Real-time developer notifications.</span></aside> <p>Your app needs to handle the state changes that are described in the following sections.</p> <h3 id="new" data-text="New subscriptions">New subscriptions</h3> <p>Be sure to follow our recommendations for <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate#process">handling new purchases</a>. When a subscription is purchased, the subscription is then returned by <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">BillingClient.queryPurchases()</code></a>, and a <code translate="no" dir="ltr">SUBSCRIPTION_PURCHASED</code> notification is sent. When you receive this notification, your app should query the Google Play Developer API to get the latest <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription state</a>. The subscription resource looks similar to the following:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: next_renewal_date, &#34;autoRenewing&#34;: true, ... &#34;paymentState&#34;: 1 # Payment received } </code></pre> <h3 id="renewals" data-text="Renewals">Renewals</h3> <aside class="note"><strong>Note:</strong><span> Subscription renewals do not need to be acknowledged.</span></aside> <p>If a subscription renews succesfully, the subscription continues to be returned by <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">BillingClient.queryPurchases()</code></a>.</p> <p>A <code translate="no" dir="ltr">SUBSCRIPTION_RENEWED</code> notification is also sent when a subscription renews. Your app should make sure the user is still entitled to the subscription and then update the subscription state with the new <code translate="no" dir="ltr">expiryTimeMillis</code> provided in the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a> returned from the Google Play Developer API. The subscription resource looks similar to the following:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: updated_expiration_time, &#34;autoRenewing&#34;: true, ... &#34;paymentState&#34;: 1 # Payment received } </code></pre> <h3 id="expirations" data-text="Expirations">Expirations</h3> <p>Once a subscription expires, the subscription is no longer returned in <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">BillingClient.queryPurchases()</code></a> and the user should lose access to the subscription.</p> <p>A <code translate="no" dir="ltr">SUBSCRIPTION_EXPIRED</code> notification is also sent when a subscription expires. When you receive this notification, your app should query the Google Play Developer API to get the latest <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription state</a>. The subscription resource looks similar to the following:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: expiry_time_in_past, &#34;autoRenewing&#34;: false, ... &#34;paymentState&#34;: 1 # Payment received } </code></pre> <h3 id="cancel" data-text="Cancellations">Cancellations</h3> <p>A user can voluntarily cancel a subscription from the Play Store or have their subscription automatically cancelled if they don&#39;t recover after being in <a href="#account-hold">account hold</a>. When a user cancels a subscription they retain access to the content until the end of the current billing cycle. When the billing cycle ends, access is revoked.</p> <p>When a subscription is cancelled but not yet <a href="#expirations">expired</a>, it is returned from <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">BillingClient.queryPurchases()</code></a>. Cancelling a subscription triggers a <code translate="no" dir="ltr">SUBSCRIPTION_CANCELED</code> notification. When you receive this notification, the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a> returned from the Google Play Developer API contains <code translate="no" dir="ltr">autoRenewing = false</code>, and the <code translate="no" dir="ltr">expiryTimeMillis</code> contains the date when the user should lose access to the subscription. If <code translate="no" dir="ltr">expiryTimeMillis</code> is in the past, then the user loses entitlement immediately. Otherwise, the user should retain entitlement until it is expired. The subscription resource looks similar to the following:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: expiry_time, &#34;autoRenewing&#34;: false, ... &#34;paymentState&#34;: 1 # Payment received &#34;cancelReason&#34;: integer # Reason the subscription was cancelled: user, billing issue, etc. } </code></pre> <p>You app can look at the <code translate="no" dir="ltr">cancelReason</code> in the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a> returned from the Google Play Developer API to learn why the subscription was cancelled (e.g. the customer cancelled or had billing issues). If the subscription was cancelled by the user, your app can look at the <code translate="no" dir="ltr">cancelSurveyResult</code> field to learn why the user cancelled the subscription.</p> <p>Your app might want to display a message in your app informing the user that their subscription was cancelled, such as &quot;Your subscription will expire on _some<em>date</em>. Your app can also <a href="#deep-link">deep link to the Google Play Store</a> to let users <a href="#restore">restore their subscription</a>.</p> <p>If you display this message, you should also offer users the ability to permanently dismiss the message.</p> <p>Note also that cancellation messages might frustrate users, especially users who manually cancelled a subscription as opposed to having their subscription cancelled because their payment was outdated. You might choose not to inform users who manually cancelled a subscription.</p> <aside class="warning"><strong>Warning:</strong><span> Don&#39;t remove a subscription from Google Play while any user is still entitled to the content. Removing content to which a user is entitled results in penalties.</span></aside> <h3 id="revoke" data-text="Revocations">Revocations</h3> <p>A subscription can be revoked from a user for a variety of reasons, including your app revoking the subscription by using <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/revoke"><code translate="no" dir="ltr">Purchases.subscriptions:revoke</code></a> or the purchase being charged back. In this situation, your app should revoke entitlement from the user immediately. A revoked subscription is no longer returned from <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">BillingClient.queryPurchases()</code></a>. A <code translate="no" dir="ltr">SUBSCRIPTION_REVOKED</code> notification is also sent when this occurs. When you receive this notification, the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a> returned from the Google Play Developer API contains <code translate="no" dir="ltr">autoRenewing = false</code>, and <code translate="no" dir="ltr">expiryTimeMillis</code> contains the date when the user should lose access to the subscription. The subscription resource looks similar to the following:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: expiry_time_in_past, &#34;autoRenewing&#34;: false, ... &#34;paymentState&#34;: 1 # Payment received } </code></pre> <h3 id="account-hold" data-text="Account hold">Account hold</h3> <p><em>Account hold</em> is a subscription state that begins when a user&#39;s form of payment fails and any associated <a href="#grace">grace period</a> has ended without payment resolution. When a subscription enters into account hold, you should block access to your content or service. The account hold period lasts for up to 30 days.</p> <p>During account hold, the subscription is not returned by <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">BillingClient.queryPurchases()</code></a>.</p> <p>During account hold, you should handle any <a href="#cancel">cancellations</a>, <a href="#restore">restorations</a>, or repurchases of your subscriptions as needed.</p> <aside class="note"><strong>Note:</strong><span> If a user fixes their payment method and recovers their subscription, the purchase token is identical to what it was before the user&#39;s account hold started. It&#39;s possible, however, that the user regained access to the subscribed content by repurchasing the subscription during the hold period. In this case, a new purchase token value is returned to represent this new subscription instance.</span></aside> <p>When a user enters into account hold, you should leverage Real-time developer notifications to inform your user why access to the subscription was suspended. Within your app, you should provide a message with instructions on how to fix their payment method and regain access to the subscription. Your message should include <a href="#deep-link">a link to the Google Play subscription settings</a> so that they can fix their payment method. As an example, you might use a message similar to the following:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">&#34;There is a problem with your subscription. Click here to go to the Google Play subscription settings to fix your payment method.&#34; </code></pre> <p>If your users can access subscription content outside of your app, you might want to send a push notification or an email to the user to let them know that their subscription is no longer active.</p> <p>If your customer was able to fix their payment issue, you can display a message in your app informing users when their subscription was restored. As an example, you might use a message similar to the following:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">&#34;Your form of payment was updated, and your subscription has been recovered.&#34; </code></pre> <p>With <a href="/web/20210507003611/https://developer.android.com/google/play/billing/getting-ready#configure-rtdn">Real-time developer notifications</a>, you receive a <code translate="no" dir="ltr">SUBSCRIPTION_ON_HOLD</code> notification when a subscription enters account hold. Call the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/get">Google Play Developer API</a> from your secure backend server to retrieve the new subscription information. During account hold, the <code translate="no" dir="ltr">expiryTimeMillis</code> of the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a> is set to a past timestamp, and <code translate="no" dir="ltr">paymentState</code> is set to <code translate="no" dir="ltr">0</code>:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: timestamp_in_past, &#34;autoRenewing&#34;: true, ... &#34;paymentState&#34;: 0 # Payment pending } </code></pre> <p>Once the user fixes their payment method, the subscription returns to an active state, and you must then restore access to the subscribed content.</p> <p>If your app relies solely on <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">queryPurchases()</code></a> to determine whether a user is entitled to a subscription, then your app should automatically handle the subscription recovering from account hold.</p> <p>If your app synchronizes subscription state with a backend, your app should listen for the <code translate="no" dir="ltr">SUBSCRIPTION_RECOVERED</code> notification to be notified when a subscription is recovered and the user should regain access. If you query for a subscription after receiving this notification, the <code translate="no" dir="ltr">expiryTimeMillis</code> is set to a timestamp in the future, and <code translate="no" dir="ltr">paymentState</code> is <code translate="no" dir="ltr">1</code>:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: timestamp_in_future, &#34;autoRenewing&#34;: true, ... &#34;paymentState&#34;: 1 # Payment received } </code></pre> <p>If the user does not fix their payment method before the end of the account hold period, you receive a <code translate="no" dir="ltr">SUBSCRIPTION_CANCELED</code> Real-time developer notification. For instructions on handling a cancellation, see <a href="#cancel">subscription cancellations</a>. When you query for the subscription that was cancelled in this way, the returned <code translate="no" dir="ltr">expiryTimeMillis</code> is set to a past timestamp, and the <code translate="no" dir="ltr">cancelReason</code> has a value of <code translate="no" dir="ltr">1</code>:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: timestamp_in_past, &#34;autoRenewing&#34;: false, ... &#34;cancelReason&#34;: 1 # The system cancelled the subscription } </code></pre> <h3 id="grace" data-text="Grace period">Grace period</h3> <aside class="note"><strong>Note:</strong><span> By default, all subscriptions have grace period enabled. You can disable grace period for a SKU from the Google Play Console.</span></aside> <p>If grace period is enabled, subscriptions enter grace period if there are payment issues at the end of a billing cycle. During this time, the user should still have access to the subscription while Google Play tries to renew the subscription. You can specify the length of a grace period from the in-app product settings in the Google Play Console.</p> <p>If your app relies solely on <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">queryPurchases()</code></a> to check whether a user is entitled to a subscription, then your app should automatically handle grace period, as <code translate="no" dir="ltr">queryPurchases()</code> continues to return cancelled purchases before their expiration dates.</p> <p>If your app synchronizes subscription state with a backend, your app should listen for the <code translate="no" dir="ltr">SUBSCRIPTION_IN_GRACE_PERIOD</code> Real-time developer notification to be notified when the user enters a grace period. While the user is in a grace period, the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a> contains <code translate="no" dir="ltr">autoRenewing = true</code> and <code translate="no" dir="ltr">paymentState = 0</code> (i.e. pending).</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: timestamp_in_future, &#34;autoRenewing&#34;: true, ... &#34;paymentState&#34;: 0 # Payment pending } </code></pre><aside class="note"><strong>Note:</strong><span> Google Play dynamically extends the <code translate="no" dir="ltr">expiryTimeMillis</code> value until the grace period has expired.</span></aside> <p>When a user enters a grace period, you should display a message in your app that tells users how to fix their payment method. Otherwise, the user loses access to subscription when the grace period ends. This message can <a href="#deep-link">deep link to the Google Play Store</a> to help the user manage their subscription.</p> <p>As soon as the user fixes their payment method, the subscription renews, and your app can handle the renewal as described in <a href="#renewals">renewals</a>.</p> <p>If the user does not fix their payment method during grace period, the subscription enters <a href="#account-hold">account hold</a>.</p> <h3 id="pause" data-text="Paused subscriptions">Paused subscriptions</h3> <aside class="note"><strong>Note:</strong><span> All subscriptions have pause enabled by default. You can disable pause from the <a href="https://web.archive.org/web/20210507003611/https://support.google.com/googleplay/android-developer/answer/140504#pauses">Google Play Console</a>.</span></aside> <p>You can prevent voluntary churn by enabling users to pause their subscription. When you enable the pause feature, users can choose to pause their subscription for a period of time between one week and three months, depending on the recurring period. Once enabled, the pause option surfaces both in the subscriptions center and in the cancel flow. Note that annual subscriptions cannot be paused, and the pause limits of one week and three months are subject to change at any time.</p> <p>To enable users to pause their subscription, do the following:</p> <ol> <li>Sign in to the <a href="https://web.archive.org/web/20210507003611/https://play.google.com/console">Google Play Console</a>.</li> <li>Select your app, and then go to <strong>Store presence &gt; In-app products &gt; Subscriptions</strong>.</li> <li>Expand the <strong>Subscription settings</strong> section.</li> <li>Check <strong>Activate Pause</strong>.</li> </ol> <p>A subscription pause takes effect only after the current billing period ends. While the subscription is paused, the user doesn&#39;t have access to the subscription. At the end of the pause period, the subscription resumes, and Google attempts to renew the subscription. If the resume is successful, the subscription becomes active again. If the resume fails due to a payment issue, the user enters the account hold state, as shown in figure 1:</p> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/pause-then-account-hold.png" alt="A user pauses their subscription and then enters account hold"/> <figcaption><b>Figure 1.</b> A user pauses their subscription and then enters account hold.</figcaption> </figure> <p>A user can also choose to manually resume a subscription at any time during the pause period, as shown in figure 2. When a user resumes manually, the billing date changes to the manual resume date.</p> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/pause-then-resume.png" alt="A user pauses and then resumes their subscription"/> <figcaption><b>Figure 2.</b> A user pauses and then resumes their subscription.</figcaption> </figure> <p>When a user&#39;s subscription is paused, the subscription is not returned by <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">queryPurchases()</code></a>. If the subscription is resumed, the subscription is then returned by <code translate="no" dir="ltr">queryPurchases()</code>.</p> <p>If your app synchronizes subscription state with a secure backend server, your app should listen to Real-time developer notifications to maintain state. These notifications also allow you to notify your users in your app that they have paused their subscription and don&#39;t have access to it. You should also provide a way for the user to manually resume the subscription by using a <a href="#deep-link">deep link to Google Play</a>.</p> <p>A <code translate="no" dir="ltr">SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED</code> Real-time developer notification is sent when your user initiates a pause of their subscription. At this time, the user should keep access to their subscription, and the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a> contains <code translate="no" dir="ltr">autoRenewing = true</code>, <code translate="no" dir="ltr">paymentState = 1</code> (Payment Received), and future values for <code translate="no" dir="ltr">expiryTimeMillis</code> and <code translate="no" dir="ltr">autoResumeTimeMillis</code>.</p> <p>A <code translate="no" dir="ltr">SUBSCRIPTION_PAUSED</code> Real-time developer notification is sent when the pause goes into effect. At this time, the user should lose access to their subscription, and the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a> contains <code translate="no" dir="ltr">autoRenewing = true</code>, and <code translate="no" dir="ltr">paymentState = 0</code> (pending), a future value for <code translate="no" dir="ltr">autoResumeTimeMillis</code>, and a past value for <code translate="no" dir="ltr">expiryTimeMillis</code>.</p> <p>A <code translate="no" dir="ltr">SUBSCRIPTION_RENEWED</code> Real-time developer notification is sent if the subscription is resumed either automatically at the end of the pause period or if the user chose to manually resume the subscription. This should be handled as described in <a href="#renewals">renewals</a>.</p> <p>A <code translate="no" dir="ltr">SUBSCRIPTION_ON_HOLD</code> Real-time developer notification is sent if there was a payment failure while trying to resume the subscription. This should be handled as described in the <a href="#account-hold">account hold section</a>.</p> <h3 id="restore" data-text="Restorations">Restorations</h3> <aside class="note"><strong>Note:</strong><span> Supporting subscription restorations is required for all developers.</span></aside> <p>A cancelled subscription remains visible in the Play Store app until its expiration date. A user can restore a cancelled subscription before it expires by clicking <strong>Resubscribe</strong> (previously <strong>Restore</strong>) in the <strong>Subscriptions</strong> section in the Google Play Store app.</p> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/resubscribe.jpg" alt="subscriptions section in the google play store app showing a cancelled subscription with a resubscribe button" width="200px"/> <figcaption><b>Figure 3.</b> <i>Account &gt; Subscriptions</i> section in the Google Play Store app showing a cancelled subscription with a <b>Resubscribe</b> button.</figcaption> </figure> <p>If your app relies solely on <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">queryPurchases()</code></a> to determine whether a user is entitled to a subscription, then your app should automatically handle restorations, as <code translate="no" dir="ltr">queryPurchases()</code> continues to return cancelled purchases before their expiration dates. A restored subscription continues to renew as if it was not cancelled.</p> <p>If your app synchronizes subscription state with a backend, your app should listen for the <code translate="no" dir="ltr">SUBSCRIPTION_RESTARTED</code> Real-time developer notification. Once received, your app can respond to the notification, record that the subscription is now set to renew, and stop displaying restoration messaging in your app. The subscription resource looks similar to the following:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: expiry_time_in_future, &#34;autoRenewing&#34;: true, ... &#34;paymentState&#34;: 1 # Payment received } </code></pre><aside class="note"><strong>Note:</strong><span> A restored subscription uses the same the <code translate="no" dir="ltr">purchaseToken</code> from when the subscription was cancelled. All cancellation fields are cleared from the resource.</span></aside> <h3 id="upgrade-downgrade" data-text="Upgrades, downgrades, and resignups">Upgrades, downgrades, and resignups</h3> <p>When a user <a href="/web/20210507003611/https://developer.android.com/google/play/billing/subs#change">upgrades</a>, <a href="/web/20210507003611/https://developer.android.com/google/play/billing/subs#change">downgrades</a>, or <a href="/web/20210507003611/https://developer.android.com/google/play/billing/subs#resubscribe">resubscribes</a>, the old subscription is invalidated, and a <a href="#new">new subscription</a> is created with a new purchase token.</p> <p>In addition, the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a> returned from the Google Play Developer API will contain a <code translate="no" dir="ltr">linkedPurchaseToken</code> that indicates the old purchase from which the user upgraded, downgraded, or resubscribed. You can use the <code translate="no" dir="ltr">linkedPurchaseToken</code> to look up the old subscription and identify the existing user account so that you can associate the new purchase with the same account. We also recommend that you use the Google Play Developer API to <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/acknowledge">acknowledge the purchase</a> to reduce user friction. The subscription resource looks similar to the following:</p> <pre class="prettyprint lang-json" translate="no" dir="ltr"><code translate="no" dir="ltr">{ &#34;kind&#34;: &#34;androidpublisher#subscriptionPurchase&#34;, ... &#34;expiryTimeMillis&#34;: next_renewal_date, &#34;autoRenewing&#34;: true, &#34;linkedPurchaseToken&#34;: old_purchase_token ... &#34;paymentState&#34;: 1 # Payment received } </code></pre> <h2 id="deep-link" data-text="Use deep links to allow users to manage a subscription">Use deep links to allow users to manage a subscription</h2> <p>As a developer, you must make it easy for your customers to manage their subscription. Your app should include a link on a settings or preferences screen that allows users to manage their subscriptions. An example of this link is shown in figure 4.</p> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/manage-subscription-link_2x.webp" alt="The Google Play Subscriptions button in this image is an example of a 'manage subscriptions' link." width="200px"/> <figcaption><b>Figure 4.</b> The <b>Google Play Subscriptions</b> button is an example of a "Manage subscriptions" link.</figcaption> </figure> <p>In this link&#39;s click handler, add logic to determine whether the user has any non-expired subscriptions for your app, where <code translate="no" dir="ltr">expiryTimeMillis</code> is in the future or <code translate="no" dir="ltr">autoRenewing</code> is set to <code translate="no" dir="ltr">true</code>.</p> <p>Each subscription&#39;s SKU matches the product ID that you assigned to it when creating it in the Play Console. To programmatically determine the SKU for an existing subscription, query your app&#39;s backend for a list of subscriptions associated with a particular user.</p> <p>If the user has a non-expired subscription, you can direct them to a URL similar to the following, replacing &quot;your-sub-product-id&quot; and &quot;your-app-package&quot; with the subscription ID and app package info:</p> <pre class="devsite-click-to-copy" translate="no" dir="ltr"><code translate="no" dir="ltr">https://play.google.com/store/account/subscriptions?sku=your-sub-product-id&amp;package=your-app-package </code></pre> <p>If a user doesn&#39;t have any non-expired subscriptions within your app, use the following URL to direct them to the page that shows all of their other subscriptions, as shown in figures 5 and 6:</p> <pre class="devsite-click-to-copy" translate="no" dir="ltr"><code translate="no" dir="ltr">https://play.google.com/store/account/subscriptions </code></pre> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/manage-all-subscriptions_2x.webp" alt="The Play Store subscriptions screen shows status for all of a user's subscriptions." width="200px"/> <figcaption><b>Figure 5.</b> The Play Store subscriptions screen shows status for all of a user's subscriptions.</figcaption> </figure> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/manage-app-subscription_2x.webp" alt="Tap on a subscription to see additional details." width="200px"/> <figcaption><b>Figure 6.</b> Tap on a subscription to see additional details.</figcaption> </figure> <p>You can find example code for subscription link logic in the <a href="https://web.archive.org/web/20210507003611/https://github.com/android/play-billing-samples/blob/52f85ddb6acc019b6b405ca68956d698ca96d640/ClassyTaxiJava/app/src/main/java/com/example/android/classytaxijava/ui/MainActivity.java#L119-L136" class="external">Classy Taxi sample app</a>.</p> <h2 id="change" data-text="Allow users to upgrade, downgrade, or change their subscription">Allow users to upgrade, downgrade, or change their subscription</h2> <p>You can offer users different subscription tiers, such as a base tier and a premium tier. Figure 7 shows a screen that offers two subscription tiers:</p> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/sub-tiers.png" alt="this app contains two subscription tiers" width="200px"/> <figcaption><b>Figure 7.</b> This app has two subscription tiers.</figcaption> </figure> <p>Users should be able to access a screen similar to figure 7 to upgrade or downgrade a subscription. When upgrading or downgrading a subscription, you can set the <em>proration mode</em>, or how the change affects your subscribers. The following table lists available proration modes:</p> <table> <tr><th>Proration mode</th><th>Description</th></tr> <tr> <td><code translate="no" dir="ltr">IMMEDIATE_WITH_TIME_PRORATION</code></td> <td>The subscription is upgraded or downgraded immediately. Any time remaining is adjusted based on the price difference, and credited toward the new subscription by pushing forward the next billing date. This is the default behavior.</td> </tr> <tr> <td><code translate="no" dir="ltr">IMMEDIATE_AND_CHARGE_PRORATED_PRICE</code></td> <td>The subscription is upgraded immediately, and the billing cycle remains the same. The price difference for the remaining period is then charged to the user.</td> </tr> <tr> <td><code translate="no" dir="ltr">IMMEDIATE_WITHOUT_PRORATION</code></td> <td>The subscription is upgraded or downgraded immediately, and the new price is charged when the subscription renews. The billing cycle remains the same.</td> </tr> <tr> <td><code translate="no" dir="ltr">DEFERRED</code></td> <td>The subscription is upgraded or downgraded only when the subscription renews.</td> </tr> </table> <h3 id="proration" data-text="Proration examples">Proration examples</h3> <p>To understand how each proration mode works, consider the following scenario:</p> <p>Samwise has a subscription to online content from the Country Gardener app. He currently has a monthly subscription to the <strong>Tier 1</strong> version of the content, which is text-only. This subscription costs him <strong>$2 per month</strong>, and it renews on the first of the month.</p> <p>On April 15, Samwise chose to upgrade to the annual version of the <strong>Tier 2</strong> subscription, which includes video updates and costs <strong>$36 per year</strong>.</p> <p>When upgrading the subscription, the developer selects a proration mode. The following list describes how each proration mode affects Samwise&#39;s subscription:</p> <dl> <dt><code translate="no" dir="ltr">IMMEDIATE_WITH_TIME_PRORATION</code></dt> <dd>Samwise&#39;s <strong>Tier 1</strong> subscription ends immediately. Since he paid for a full month (April 1-30) but upgraded halfway through the subscription period, half of a month&#39;s subscription ($1) is applied to his new subscription. However, since that new subscription costs $36 per year, the $1 credit balance pays for only 10 days (April 16-25), so on April 26, he is charged $36 for a new subscription and another $36 on April 26th of each year following.</dd> <dt><code translate="no" dir="ltr">IMMEDIATE_AND_CHARGE_PRORATED_PRICE</code></dt> <dd>This mode can be used because the <strong>Tier 2</strong> subscription price per time unit ($36/year = $3/month) is greater than <strong>Tier 1</strong> subscription price per time unit ($2/month). Samwise&#39;s <strong>Tier 1</strong> subscription is immediately ended. Since he paid for a full month but used only half of it, half of a month&#39;s subscription ($1) is applied to his new subscription. However, since that new subscription costs $36/year, the remaining 15 days costs $1.50, so he is charged the difference of $0.50 for his new subscription, and another $35.50 on May 1. After that, Samwise is charged $36 each year following.</dd> <dt><code translate="no" dir="ltr">IMMEDIATE_WITHOUT_PRORATION</code></dt> <dd>Samwise&#39;s <strong>Tier 1</strong> subscription is immediately upgraded to <strong>Tier 2</strong> with no extra charge, and on May 1st he is charged $36 for his new subscription tier and another $36 on May 1 of each year following.</dd> <dt><code translate="no" dir="ltr">DEFERRED</code></dt> <dd>Samwise&#39;s <strong>Tier 1</strong> subscription continues until it expires on April 30. On May 1st, the <strong>Tier 2</strong> subscription takes effect, and Samwise is charged $36 for his new subscription tier.</dd> </dl> <p>When choosing a proration mode, be sure to review our <a href="#proration-recommendations">proration recommendations</a>.</p> <p>Your app can offer users an upgrade or downgrade using the same steps as with <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate#launch">launching a purchase flow</a>. However, when upgrading or downgrading, you need to provide details for the current subscription, the future (upgraded or downgraded) subscription, and the proration mode to use, as shown in the following example:</p> <div> <div class="ds-selector-tabs"><section><h3 id="kotlin" data-text="Kotlin">Kotlin</h3> <pre class="prettyprint lang-kotlin" translate="no" dir="ltr"> // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync() val flowParams = BillingFlowParams.newBuilder() .setOldSku(previousSku, purchaseTokenOfOriginalSubscription) .setReplaceSkusProrationMode(desiredProrationMode) .setSkuDetails(upgradeOrDowngradeSkuDetails) .build(); val responseCode = billingClient.launchBillingFlow(activity, flowParams) </pre> </section><section><h3 id="java" data-text="Java">Java</h3> <pre class="prettyprint lang-java" translate="no" dir="ltr"> // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync() BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setOldSku(previousSku, purchaseTokenOfOriginalSubscription) .setReplaceSkusProrationMode(desiredProrationMode) .setSkuDetails(upgradeOrDowngradeSkuDetails) .build(); int responseCode = billingClient.launchBillingFlow(billingFlowParams); </pre> </section></div> </div> <p>For the immediate replacement proration modes, your app receives the new purchase in your <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/PurchasesUpdatedListener"><code translate="no" dir="ltr">PurchasesUpdatedListener</code></a>. The purchase is also available in <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">BillingClient.queryPurchases()</code></a>. When you receive the purchase token, follow the same <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate#process">verification process</a> as with verifying a new purchase token. Make sure to acknowledge these purchases with <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#acknowledgepurchase"><code translate="no" dir="ltr">BillingClient.acknowledgePurchase()</code></a> from the Google Play Billing Library or <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/acknowledge"><code translate="no" dir="ltr">Purchases.subscriptions:acknowledge</code></a> from the Google Play Developer API.</p> <p>The Google Play Developer API returns a <code translate="no" dir="ltr">linkedPurchaseToken</code> in the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a>. Be sure to invalidate the token provided in the <code translate="no" dir="ltr">linkedPurchaseToken</code> to ensure that the old token is not used to gain access to your services. See <a href="#upgrade-downgrade">Upgrades, downgrades, and resignups</a> for information on handling upgrade and downgrade purchases.</p> <p>For the deferred replacement mode, your app receives a call to your <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/PurchasesUpdatedListener"><code translate="no" dir="ltr">PurchasesUpdatedListener</code></a> with an empty list of purchases and a status of whether the upgrade or downgrade was successful. Until the replacement takes effect, <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases"><code translate="no" dir="ltr">BillingClient.queryPurchases()</code></a> continues to return the purchase for the original subscription plan. Once the new plan takes effect, <code translate="no" dir="ltr">queryPurchases()</code> returns the purchase data for the new subscription, and a <code translate="no" dir="ltr">SUBSCRIPTION_RENEWED</code> notification is sent to your secure backend server. For deferred replacements, it is <strong>strongly recommended</strong> to listen to this notification and to acknowledge the purchase using <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/acknowledge"><code translate="no" dir="ltr">Purchases.subscriptions:acknowledge</code></a>. The <code translate="no" dir="ltr">linkedPurchaseToken</code> in the subscription resource can be used to determine which user in your subscription backend, if applicable, should be updated with the new entitlement. Your app should not rely on the user opening the app and acknowledging via <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#acknowledgepurchase"><code translate="no" dir="ltr">BillingClient.acknowledgePurchase()</code></a>, since the user might not open the app within three days of the plan change taking effect.</p> <h3 id="upgrade-free-trial" data-text="Upgrading with free trial or intro price offers">Upgrading with free trial or intro price offers</h3> <p><a href="#free-trial">Free trial</a> eligibility settings apply when a user is upgrading or downgrading. You can adjust the free trial eligibility settings in the Google Play Console.</p> <p>Note the following:</p> <ul> <li>If users can receive only one free trial across all available subscriptions in your app, the plan the user is changing to will not have a free trial or intro price.</li> <li>If you provide one free trial per subscription product, the plan the user is changing to may have a free trial or intro price.</li> </ul> <p>The following table describes the behavior of each proration mode if both the new and old plans have a free trial, and the user is upgrading during a free trial:</p> <table> <tr> <td></td> <td>One free trial per app</td> <td>One free trial per subscription product</td> </tr> <tr> <td>IMMEDIATE_WITH_TIME_PRORATION</td> <td>The user loses the free trial immediately. The remaining free trial period is converted to an equivalent free period of the new tier based on the price difference.</td> <td>The user loses the previous free trial but immediately starts the new free trial. In addition, the remaining free trial period of the old tier is converted to an equivalent free period of the new tier and added to the new free trial.</td> </tr> <tr> <td>IMMEDIATE_AND_CHARGE_PRORATED_PRICE</td> <td colspan="2"> <p>The user loses the free trial immediately. The price difference for the remaining period is then charged to the user. The next billing date remains unchanged.</p> <p class="note"><b>Note:</b> This option is available only for a subscription upgrade, where the price per unit of time increases.</p></td> </tr> <tr> <td>IMMEDIATE_WITHOUT_PRORATION</td> <td colspan="2">The user is immediately upgraded to the new tier. The user keeps free trial access to the new tier until the previous billing period ends.</td> </tr> <tr> <td>DEFERRED</td> <td colspan="2">The user keeps free trial access to the old subscription until the next billing date.</td> </tr> </table> <p>To understand how free trial transitions work in the default case of one free trial per app, consider the following scenario:</p> <p>Maria has a subscription to online content from the Country Gardener app. She currently has a monthly subscription to the <strong>Tier 1</strong> version of the content, which is text-only. This subscription costs her <strong>$10/month</strong>, and she subscribed on April 1. She is enjoying a 30-day free trial as a first-time subscriber, which means her first payment is due on May 1.</p> <p>On April 15, Maria chooses to upgrade to the <strong>Tier 2</strong> subscription, which includes video updates and costs <strong>$20/month</strong>. This second subscription has a 30-day trial as well.</p> <p>The following list describes how the free trial transition for each proration mode:</p> <ul> <li><code translate="no" dir="ltr">IMMEDIATE_WITH_TIME_PRORATION</code> - Maria is upgraded to <strong>Tier 2</strong> immediately. Since Maria upgraded halfway through the subscription period, half of the month&#39;s subscription (15 days valued at $10/month) is applied to her new subscription. However, since that new subscription costs $20/month, the 15 day balance pays for only 7.5 days. Maria is not eligible for another free trial to <strong>Tier 2</strong>, so starting April 22, she is charged $20 every month.</li> <li><code translate="no" dir="ltr">IMMEDIATE_AND_CHARGE_PRORATED_PRICE</code> - This mode can be used because the <strong>Tier 2</strong> subscription price per time unit ($20/month) is greater than the <strong>Tier 1</strong> subscription price per time unit ($10/month). Maria&#39;s <strong>Tier 1</strong> subscription is immediately upgraded to <strong>Tier 2</strong>, and she loses her free trial. Since Maria&#39;s next billing date was May 1, she is charged $10 today to cover the 2nd half of April, then starting May 1 she is charged $20 every month.</li> <li><code translate="no" dir="ltr">IMMEDIATE_WITHOUT_PRORATION</code> - Maria&#39;s <strong>Tier 1</strong> subscription is immediately upgraded to <strong>Tier 2</strong>. Maria keeps her free trial until April 30 and now has access to <strong>Tier 2</strong> content. Starting May 1, she is charged $20 every month.</li> <li><code translate="no" dir="ltr">DEFERRED</code> - Maria&#39;s <strong>Tier 1</strong> subscription continues until the next payment is due on May 1. On May 1, the <strong>Tier 2</strong> subscription takes effect, and Maria is charged $20 on the first of every month.</li> </ul> <p>The following list describes the transition behavior if the developer instead allows one free trial per subscription:</p> <ul> <li><code translate="no" dir="ltr">IMMEDIATE_WITH_TIME_PRORATION</code> - Maria is upgraded to <strong>Tier 2</strong> immediately. Since Maria upgraded halfway through the subscription period, half of the month&#39;s subscription (15 days valued at $10/month) is applied to her new subscription. However, since that new subscription costs $20/month, the 15 day balance pays for only 7.5 days. Maria is eligible for another free trial to <strong>Tier 2</strong>, so she is not charged for another 37.5 days. Starting May 22, she is charged $20 every month.</li> <li><code translate="no" dir="ltr">IMMEDIATE_AND_CHARGE_PRORATED_PRICE</code> - This mode can be used because the <strong>Tier 2</strong> subscription price per time unit ($20/month) is greater than the <strong>Tier 1</strong> subscription price per time unit ($10/month). Maria&#39;s <strong>Tier 1</strong> subscription is immediately upgraded to <strong>Tier 2</strong>, and she loses her free trial. Since Maria&#39;s next billing date was May 1, she is charged $10 today to cover the 2nd half of April, then starting May 1 she is charged $20 every month.</li> <li><code translate="no" dir="ltr">IMMEDIATE_WITHOUT_PRORATION</code> - Maria&#39;s <strong>Tier 1</strong> subscription is immediately upgraded to <strong>Tier 2</strong>. Maria keeps her free trial until April 30 and now has access to <strong>Tier 2</strong>.</li> <li><code translate="no" dir="ltr">DEFERRED</code> - Maria&#39;s <strong>Tier 1</strong> subscription continues until the next payment is due on May 1. On May 1, the <strong>Tier 2</strong> subscription takes effect, and Maria is charged $20 on the first of every month.</li> </ul> <h3 id="proration-recommendations" data-text="Proration recommendations">Proration recommendations</h3> <p>The following table shows diferrent proration scenarios along with what we recommend for each scenario:</p> <table> <tr> <th>Scenario</th> <th>Recommended proration mode</th> <th>Result</th> </tr> <tr> <td>Upgrading to a more expensive tier</td> <td><code translate="no" dir="ltr">IMMEDIATE_AND_CHARGE_PRORATED_PRICE</code></td> <td>The user receives access immediately while keeping the same billing period.</td> </tr> <tr> <td>Downgrading to a less expensive tier</td> <td><code translate="no" dir="ltr">DEFERRED</code></td> <td>The user already paid for the more expensive tier, so they will keep access until the next billing date.</td> </tr> <tr> <td>Changing recurring period on the same tier (for example, monthly to annual)</td> <td><code translate="no" dir="ltr">DEFERRED</code></td> <td>The user will pay the new recurring price at the next billing date.</td> </tr> <tr> <td>Upgrading while in a free trial, keeping the trial</td> <td><code translate="no" dir="ltr">IMMEDIATE_WITHOUT_PRORATION</code></td> <td>The user keeps free trial access, but upgrades to a higher tier for the remainder of the trial.</td> </tr> <tr> <td>Upgrading while in a free trial - ending access to the free trial</td> <td><code translate="no" dir="ltr">IMMEDIATE_AND_CHARGE_PRORATED_PRICE</code></td> <td>The user receives access to the new tier immediately but no longer has a free trial.</td> </tr> </table> <h2 id="winback" data-text="Winback after churn">Winback after churn</h2> <p>After a user has cancelled their subscription, you can try to win them back either in your app, or through the Play store. The following table describes various subscription scenarios along with associated winback actions and app requirements.</p> <table> <tr> <td></td> <td colspan="2" style="background-color:#f1f3f4;border-left:solid black thin;border-right:solid black thin"> <strong>Before subscription expiration</strong></td> <td colspan="2"><strong>After subscription expiration</strong></td> </tr> <tr style="border-bottom:solid black thin"> <td></td> <td style="background-color:#f1f3f4;border-left:solid black thin"> <strong>In-app</strong></td> <td style="background-color:#f1f3f4;border-right:solid black thin"> <strong>In Play Store</strong></td> <td><strong>In-app</strong></td> <td><strong>In Play Store</strong></td> </tr> <tr> <td><b>Winback feature</b></td> <td style="background-color:#f1f3f4;border-left:solid black thin">In-app subscription</td> <td style="background-color:#f1f3f4;border-right:solid black thin">Restore</td> <td>In-app subscription</td> <td>Resubscribe</td> </tr> <tr> <td><b>User goes through checkout flow</b></td> <td style="background-color:#f1f3f4;border-left:solid black thin">Yes</td> <td style="background-color:#f1f3f4;border-right:solid black thin">No</td> <td>Yes</td> <td>Yes</td> </tr> <tr> <td><b>User subscription remains associated with the same SKU</b></td> <td style="background-color:#f1f3f4;border-left:solid black thin">User can sign up for same or different SKU</td> <td style="background-color:#f1f3f4;border-right:solid black thin">Yes</td> <td>User can sign up for same or different SKU</td> <td>Yes</td> </tr> <tr> <td><b>Creates new purchase token</b></td> <td style="background-color:#f1f3f4;border-left:solid black thin">Yes</td> <td style="background-color:#f1f3f4;border-right:solid black thin">No</td> <td>Yes</td> <td>Yes</td> </tr> <tr> <td><b>Enabled by default</b></td> <td style="background-color:#f1f3f4;border-left:solid black thin">No</td> <td style="background-color:#f1f3f4;border-right:solid black thin">Yes, support required for all devs</td> <td>No</td> <td> <p>Apps without Billing Library 2.0+: No</p> <p>Apps with Billing Library 2.0+: Yes. Devs can opt-out in Console.</p> </td> </tr> <tr> <td><b>When user is charged</b></td> <td style="background-color:#f1f3f4;border-left:solid black thin"> <p>If using same SKU: end of current billing period.</p> <p>If using different SKU: depends on proration mode.</p> </td> <td style="background-color:#f1f3f4;border-right:solid black thin">End of current billing period</td> <td>Immediately</td> <td>Immediately</td> </tr> <tr> <td><b>Implementation required</b></td> <td style="background-color:#f1f3f4;border-left:solid black thin">Provide a re-signup UI in your app</td> <td style="background-color:#f1f3f4;border-right:solid black thin"> <p>Detect change in subscription state</p> <p>Deep-link to Play Store</p> </td> <td>Provide a re-signup UI in your app</td> <td>Handle out-of-app purchases</td> </tr> </table> <h3 id="before-in-app" data-text="Before subscription expiration - in-app">Before subscription expiration - in-app</h3> <p>For subscriptions that have been canceled but have not yet expired, you can allow subscribers to restore their subscription within your app by applying the same in-app product purchase flow as for new subscribers. Ensure your UI reflects that the user has an existing subscription. For example, you might want to display the user&#39;s current expiration date and recurring price with a <strong>Reactivate</strong> button.</p> <p>Most of the time, you will want to offer the user the same price and SKU they were already subscribed to, as follows:</p> <ul> <li>Initiate a new subscription purchase with the same SKU.</li> <li>The new subscription replaces the old one and renews on the same expiration date. The old subscription is immediately marked as expired.</li> <li>As an example, Achilles has a subscription to Example Music App, and the subscription is due to expire on August 1. On July 10, he resubscribes to the one-month subscription at the same price per month. The new subscription is prorated with the remaining credit, is immediately active, and still renews on August 1.</li> </ul> <p>If you would like to offer a different price—for example a new free trial or a winback discount—you can instead offer a different SKU to the user:</p> <ul> <li>Initiate an <a href="#change">upgrade or downgrade</a> with the different SKU using the proration mode <code translate="no" dir="ltr">IMMEDIATE_WITHOUT_PRORATION</code>.</li> <li>The new subscription replaces the old one and renews on the same expiration date. The user is charged the price of the new SKU, including any introductory prices, on the original expiration date.</li> <li>As an example, Achilles has a subscription to Example Music App, and the subscription is due to expire on August 1. On July 10, he resubscribes to an annual subscription with an introductory price. The new subscription is immediately active, and the user is charged the introductory price on August 1.</li> <li>If you decide to include a free trial or intro price in your winback SKU, ensure that the user is eligible by unchecking the <strong>Allow one free trial per app</strong> box in the Google Play Console, which restricts the user to getting one free trial per app.</li> </ul> <p>When you receive the purchase token, <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate#process">process the purchase</a> just as you would with a new subscription. Additionally, the Google Play Developer API returns a <code translate="no" dir="ltr">linkedPurchaseToken</code> in the subscription resource. Be sure to <a href="/web/20210507003611/https://developer.android.com/google/play/billing/subs#upgrade-downgrade">invalidate the token</a> provided in the <code translate="no" dir="ltr">linkedPurchaseToken</code> to ensure that the old token is not used to gain access to your services.</p> <h3 id="before-in-store" data-text="Before subscription expiration - in Play Store">Before subscription expiration - in Play Store</h3> <aside class="note"><strong>Note:</strong><span> Supporting restore is required for all developers.</span></aside> <p>While the subscription is canceled but still active, users can restore the subscription in the Google Play subscriptions center by clicking <strong>Resubscribe</strong> (previously <strong>Restore</strong>). This keeps the same subscription and purchase token.</p> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/resubscribe.jpg" alt="subscriptions section in the google play store app showing a cancelled subscription with a resubscribe button" width="250px"/> <figcaption><b>Figure 8.</b> <i>Account &gt; Subscriptions</i> section in the Google Play Store app showing a cancelled subscription with a <b>Resubscribe</b> button.</figcaption> </figure> <p>For more information on restoring subscriptions, see <a href="#restore">Restorations</a>.</p> <h3 id="after-in-app" data-text="After subscription expiration - in-app">After subscription expiration - in-app</h3> <p>You can allow expired subscribers to resubscribe within your app by applying the same in-app product purchase flow as for new subscribers. Note the following:</p> <ul> <li>To offer users a discount, you might want to offer a product ID with special pricing for your subscription, also called a <em>winback SKU</em>. You can provide the offer in your app, or you can notify the user of the offer outside of the app, such as in email.</li> <li>To start a winback subscription, launch the purchase flow in your Android app using the Google Play Billing Library. This is the same process as with a new subscription, but you can determine the SKU that is available to the user.</li> <li>If you decide to include a free trial or intro price in your winback SKU, ensure that the user is eligible by unchecking the <strong>Allow one free trial per app</strong> box in the Google Play Console, which restricts the user to getting one free trial per app.</li> <li>If the user resubscribes to the same SKU, they are no longer eligible for free trials or introductory price. Ensure that your UI reflects this.</li> </ul> <p>When you receive the purchase token, <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate#process">process the purchase</a> just as you would with a new subscription. You will not receive a <code translate="no" dir="ltr">linkedPurchaseToken</code> in the subscription resource.</p> <h3 id="after-in-store" data-text="After subscription expiration - in Play Store">After subscription expiration - in Play Store</h3> <aside class="note"><strong>Note:</strong><span> Resubscribe from Play Store is only available to apps with Billing Library versions 2.0 and above.</span></aside><aside class="note"><strong>Note:</strong><span> All subscription SKUs for eligible apps have resubscribe enabled by default. You can opt out at any time by adjusting the SKU settings through the <a href="https://web.archive.org/web/20210507003611/https://support.google.com/googleplay/android-developer/answer/140504">Google Play Console</a>.</span></aside> <p>If enabled, users can resubscribe to the same SKU for up to one year after expiration by clicking <strong>Resubscribe</strong> in the Google Play subscriptions center. This generates a new subscription and purchase token.</p> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/resubscribe-remove.jpg" alt="subscriptions section in the google play store app showing a cancelled and expired subscription with resubscribe and remove buttons" width="250px"/> <figcaption><b>Figure 9.</b> <i>Account &gt; Subscriptions</i> section in the Google Play Store app showing a cancelled and expired subscription with <b>Resubscribe</b> and <b>Remove</b> buttons.</figcaption> </figure> <p>Resubscribing is considered an out-of-app purchase, so be sure to follow best practices for <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate#ooap">handling purchases made from outside your app</a>.</p> <h2 id="customer-management" data-text="Customer management">Customer management</h2> <p>Using Real-time developer notifications, you can detect in real time when a user decides to cancel. When a user cancels, but before their subscription has expired, you can send them push notifications or in-app messages to ask them to resubscribe. For more information, see <a href="#winback">Winback after churn</a>.</p> <h2 id="ft-ip" data-text="Free trials and introductory pricing">Free trials and introductory pricing</h2> <p>Your app can offer free trials and introductory prices to encourage customers to try your app.</p> <h3 id="free-trial" data-text="Free trial">Free trial</h3> <p>You can let your users try out a subscription before making a payment. Free trials run for a period of time that you specify and convert to full subscriptions automatically once the free trial period ends. These converted subscriptions use the same time period and price as ordinary subscriptions. You can set up a free trial for any type of subscription.</p> <p>To start a free trial, a user completes the standard process for purchasing a subscription on Google Play. If a user is eligible for a free trial, they aren&#39;t charged for the duration of the free trial, and they&#39;re notified by email that the subscription includes a free trial period. Google Play records a transaction of $0.00, and the subscription is marked as purchased for the free trial period or until its cancellation.</p> <p>Google Play verifies that the user has a valid payment method before starting the free trial. Some users may see this verification as a hold or charge on their payment method. This hold or charge is temporary and is later reversed or refunded.</p> <p>After the trial period ends, the user&#39;s payment method is charged for the full subscription amount.</p> <p>If a user cancels a subscription at any time during the free trial, the subscription remains active until the end of the trial, and they aren&#39;t charged when the free trial period ends.</p> <p>By default, users can receive only one free trial across all available subscriptions in your app. If you&#39;d like to provide one free trial per subscription product, you can change the corresponding setting in the Google Play Console.</p> <p>To add a free trial to a subscription, see the <a href="https://web.archive.org/web/20210507003611/https://support.google.com/googleplay/android-developer/answer/140504">free trial instructions</a> in the Google Play Help Center.</p> <p><a href="#lifecycle">Subscription lifecycle events</a> for a subscription with a free trial work the same way as a subscription without a free trial. The only difference is that the renewal period might differ from the regular subscription renewal interval.</p> <p>When <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate#show-products">showing your users products available for sale</a>, you can use the <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/SkuDetails#getfreetrialperiod"><code translate="no" dir="ltr">SkuDetails.getFreeTrialPeriod()</code></a> method to display that a free trial is available for a product.</p> <aside class="note"><strong>Note:</strong><span> <code translate="no" dir="ltr">SkuDetails.getFreeTrialPeriod()</code> returns the free trial period configured in Google Play Console. It&#39;s possible the user has already used a free trial. In this case, Google Play communicates to the user that they are ineligible for another free trial.</span></aside> <p>If a subscription was purchased with a free trial, the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription</a> returned from Google Play Developer API has <code translate="no" dir="ltr">paymentState = 2</code> (free trial). If the subscription successfully renews, the <code translate="no" dir="ltr">paymentState</code> switches to <code translate="no" dir="ltr">1</code> (payment received).</p> <h3 id="intro" data-text="Introductory pricing">Introductory pricing</h3> <p>Similar to free trials, your app can offer introductory prices to encourage users to try out your app. To learn more about introductory pricing and how to enable it, see <a href="https://web.archive.org/web/20210507003611/https://support.google.com/googleplay/android-developer/answer/140504">Create a subscription</a>.</p> <p><a href="#lifecycle">Subscription lifecycle events</a> for a subscription with introductory pricing work the same way as a subscription without introductory pricing. The only difference is that the renewal period might differ from the regular subscription renewal interval.</p> <p>When <a href="/web/20210507003611/https://developer.android.com/google/play/billing/integrate#show-products">showing your users products available for sale</a>, you can use <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/SkuDetails#getintroductoryprice"><code translate="no" dir="ltr">SkuDetails.getIntroductoryPrice()</code></a> and related methods to display to your user that introductory pricing is available for the subscription.</p> <aside class="note"><strong>Note:</strong><span> The introductory pricing methods in <code translate="no" dir="ltr">SkuDetails</code> return the pricing as configured in Google Play Console. It&#39;s possible the user has already used the introductory price offer for that SKU. In this case, Google Play communicates to the user that they are ineligible to receive the introductory pricing again.</span></aside> <h2 id="promote" data-text="Promote your subscription">Promote your subscription</h2> <p>You can create promotion codes to give selected users an extended free trial to an existing subscription SKU. To learn more, see <a href="/web/20210507003611/https://developer.android.com/google/play/billing/promo">Promo codes</a>.</p> <h2 id="cancel-refund-revoke" data-text="Cancel, refund, or revoke">Cancel, refund, or revoke</h2> <p>You can use the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">Google Play Developer API</a> to <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/cancel">cancel</a>, <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/refund">refund</a>, or <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/revoke">revoke</a> a subscription. This functionality is also available in the <a href="https://web.archive.org/web/20210507003611/https://support.google.com/googleplay/android-developer/answer/2741495">Google Play Console</a>.</p> <ul> <li><strong>Cancel</strong>: Users can cancel a subscription on Google Play. You can also provide an option for users to cancel in your app or on your website. Your app should handle these cancellations as described in <a href="#revoke">Revocations</a>.</li> <li><strong>Refund</strong>: When you refund, the user can continue to use the subscription. Refunds can be used if, for example, there was a technical error that prevented the user from accessing your product, but the error has been resolved. Note that to refund more than the most recent payment, or if you want to issue a partial refund, you must use the Google Play Console.</li> <li><strong>Revoke</strong>: When you revoke, the user immediately loses access to the subscription. This can be used if, for example, there was a technical error that prevented the user from accessing your product, and the user does not want to continue using the product. Your app should handle these cancellations as described in <a href="#revoke">Revocations</a>.</li> </ul> <p>The following table illustrates the differences between cancel, refund, and revoke.</p> <table> <tr> <td></td> <td><strong>Stops renewal</strong></td> <td><strong>Refund money</strong></td> <td><strong>Revoke access</strong></td> </tr> <tr> <td><strong> <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/cancel">Cancel</a> </strong></td> <td><strong>Yes</strong></td> <td>No</td> <td>No</td> </tr> <tr> <td><strong> <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/refund">Refund</a> </strong></td> <td>No</td> <td><strong>Yes</strong></td> <td>No</td> </tr> <tr> <td><strong> <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/revoke">Revoke</a> </strong></td> <td><strong>Yes</strong></td> <td><strong>Yes</strong></td> <td><strong>Yes</strong></td> </tr> </table> <h2 id="defer" data-text="Defer billing for a subscriber">Defer billing for a subscriber</h2> <p>You can advance the next billing date for a subscriber by using <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/defer">Purchases.subscriptions:defer</a> from the Google Play Developer API. During the deferral period, the user is subscribed to your content with full access but is not charged. The subscription renewal date is updated to reflect the new date.</p> <p>Deferred billing allows you to do the following:</p> <ul> <li>Give users free access as a special offer, such as giving one week free for purchasing a movie.</li> <li>Give free access to customers as a gesture of goodwill.</li> </ul> <p>Billing can be deferred by as little as one day and by as long as one year per API call. To defer the billing even further, you can call the API again before the new billing date arrives.</p> <p>As an example, Darcy has a monthly subscription to online content for the Fishing Quarterly app. She is normally billed £1.25 on the first of each month. In March, she participated in an online survey for the app publisher. The publisher rewards her with six free weeks by deferring the next payment until May 15, which is six weeks after her previously scheduled billing date of April 1. Darcy is not charged for April or the beginning of May and still has access to the content. On May 15, she is charged the normal £1.25 subscription fee for the month. Her next renewal date is now June 15.</p> <p>When deferring, you might want to notify the user by email or within the app to notify them that their billing date has changed.</p> <h2 id="price-change" data-text="Changing subscription prices">Changing subscription prices</h2> <p><strong>Warning:</strong> You should not change the price of a <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/news/subscribe">Subscribe with Google</a> subscription.</p> <p>Google Play allows you to sell your digital products around the world to many users in different locales with different currencies and pricing considerations. Sometimes, due to regional costs or currency fluctuations, you may decide you need to change the price of your subscription. If you are willing to keep existing subscribers on the existing price, you can create a new SKU with the updated price and offer that to new subscribers.</p> <p>If you are not able to continue supporting subscribers with the price that was offered when they signed up for your subscription and are willing to cancel all subscriptions for users that decided not to accept the new price, you can enforce a mandatory price change. If the user does not agree to the new price, their subscription is cancelled. To maximize opt-in rates and encourage your users to take action, your app should display messaging to your users about the upcoming price change. For more information about price change messaging, see <a href="#price-change-communicate">Communicating your price change</a>.</p> <p>To change change the price of a subscription, do the following:</p> <ol> <li>Sign in to the <a href="https://web.archive.org/web/20210507003611/https://play.google.com/console/">Google Play Console</a>.</li> <li>Find the app containing the subscription whose price you&#39;d like to change.</li> <li>Select <strong>Store presence &gt; In-app products</strong>, and then open the <strong>Subscriptions</strong> tab.</li> <li><p>Select the <strong>Edit</strong> link next to the price you want to change, as shown in figure 10:</p> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/edit-price.png" alt="Editing the subscription price field" width="650px"/> <figcaption><b>Figure 10.</b> Editing the subscription price field.</figcaption> </figure></li> <li><p>Enter the new subscription price.</p></li> <li><p>When you change the price, a confirmation dialog appears, as shown in figure 11.</p> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/price-change-warning.png" alt="a warning appears when you edit the subscription price" width="600px"/> <figcaption><b>Figure 11.</b> A warning appears when you edit the subscription price.</figcaption> </figure> <p>This dialog explains how the price change affects new and existing subscribers. Note the following:</p> <ul> <li>You cannot reverse the price change once you confirm.</li> <li>Google Play begins notifying your users of the price change starting seven days after confirmation.</li> <li>When <em>increasing</em> subscription price, users must approve of the price change within 30 days, or their subscription is automatically cancelled.</li> <li>Subscription price <em>decreases</em> are applied automatically for existing subscribers at their next renewal date. Anyone who subscribes after a price decrease receives the decreased price automatically.</li> </ul> <p>Click <strong>Apply</strong> to continue.</p></li> <li><p>A confirmation dialog appears that again describes when the new subscription prices take effect. <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/price-change-confirm.png" alt="confirmation dialog that shows when the subscription price change takes effect" width="600px"/> <figcaption><b>Figure 12.</b> Confirmation dialog that shows when the subscription price change takes effect.</figcaption> </figure></p></li> </ol> <h3 id="price-change-communicate" data-text="Communicate your price change to the user">Communicate your price change to the user</h3> <p>You should notify your existing subscribers whenever you make a price change, especially if the price is increasing.</p> <p>When you <em>increase</em> the price of a subscription, you have at least seven days to notify your existing subscribers about the price change before Google Play can start notifying them. When Google Play notifies users, it does so by displaying a dialog similar to the one shown in figure 13. This dialog shows the old price, the new price, and the date when the new price takes effect.</p> <aside class="note"><strong>Note:</strong><span> When <em>decreasing</em> subscription price, users do not need to agree to the change and are not shown the price change dialog.</span></aside> <figure> <img src="/web/20210507003611im_/https://developer.android.com/images/google/play/billing/agree-to-price-change.png" alt="Generic dialog notifying the user of a subscription price change" width="250px"/> <figcaption><b>Figure 13.</b> Generic dialog notifying the user of a subscription price change.</figcaption> </figure> <p>Within your app, you can display this dialog in the following ways:</p> <ul> <li><a href="#price-change-launch">Launch a price change confirmation flow</a> when users open your app.</li> <li>Send users to the subscriptions center to review the price change using a <a href="#deep-link">deep link</a>.</li> </ul> <p>Your app can determine if the user has a pending price change by looking at the <code translate="no" dir="ltr">priceChange</code> field in the <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">subscription resource</a>. If present, this field indicates the subscription has a price change, and the <code translate="no" dir="ltr">priceChange.state</code> field indicates whether the price change has been accepted or is still outstanding.</p> <h3 id="price-change-launch" data-text="Launch a price change confirmation flow">Launch a price change confirmation flow</h3> <p>To display the Google Play price change dialog when your app launches, use <a href="/web/20210507003611/https://developer.android.com/reference/com/android/billingclient/api/BillingClient#launchpricechangeconfirmationflow"><code translate="no" dir="ltr">BillingClient.launchPriceChangeConfirmationFlow()</code></a>.</p> <p>Before displaying the price change dialog, you can also present your own message or dialog that explains the reason behind the price change. If you create and show this type of custom messaging, your users are more likely to renew their subscription at the new price.</p> <p>Here&#39;s an example of launching the price change confirmation flow:</p> <div> <div class="ds-selector-tabs"><section><h3 id="kotlin" data-text="Kotlin">Kotlin</h3> <pre class="prettyprint lang-kotlin" translate="no" dir="ltr"> val priceChangeFlowParams = PriceChangeFlowParams.newBuilder() .setSkuDetails(changedPriceSubscriptionSkuDetails) .build() billingClient.launchPriceChangeConfirmationFlow(activity, priceChangeFlowParams, object : PriceChangeConfirmationListener() { override fun onPriceChangeConfirmationResult(responseCode: Int) { if (responseCode == BillingResponseCode.OK) { // User has confirmed the price change. } else if (responseCode == BillingResponseCode.USER_CANCELED) { // User hasn't confirmed the price change and should retain // access until the end of the current billing cycle. } } }) </pre> </section><section><h3 id="java" data-text="Java">Java</h3> <pre class="prettyprint lang-java" translate="no" dir="ltr"> PriceChangeFlowParams priceChangeFlowParams = PriceChangeFlowParams.newBuilder() .setSkuDetails(changedPriceSubscriptionSkuDetails) .build(); billingClient.launchPriceChangeConfirmationFlow(activity, priceChangeFlowParams, new PriceChangeConfirmationListener() { @Override public void onPriceChangeConfirmationResult(int responseCode) { if (responseCode == BillingResponseCode.OK) { // User has confirmed the price change. } else if (responseCode == BillingResponseCode.USER_CANCELED) { // User hasn't confirmed the price change and should retain // access until the end of the current billing cycle. } } }); </pre> </section></div> </div> <h3 id="price-change-confirmed" data-text="Handle user confirmation of the price change">Handle user confirmation of the price change</h3> <p>If the user accepts your subscription&#39;s new price, the subscription renews and can be processed just like any other <a href="#renewals">renewal</a>. Additionally, you receive a <code translate="no" dir="ltr">SUBSCRIPTION_PRICE_CHANGE_CONFIRMED</code> Real-time developer notification.</p> <h3 id="price-change-declined" data-text="Handle when a price change is declined">Handle when a price change is declined</h3> <p>If a user hasn&#39;t accepted your price change by the time their old subscription expires, they are then unsubscribed, and you receive a <code translate="no" dir="ltr">SUBSCRIPTION_CANCELED</code> notification. This event can be handled as described in <a href="#cancel">Cancellations</a>.</p> <h3 id="accidental" data-text="Accidental price change">Accidental price change</h3> <p>If you&#39;ve accidentally changed the price of a subscription, reverse the change immediately. As long as the price is reverted within seven days, existing subscribers are not notified about the accidental price change. Note that new subscribers might receive the accidental price during the time between the first price change and the reversion.</p> <h3 id="two-price-changes" data-text="Doing two price changes in a row">Doing two price changes in a row</h3> <p>You should ensure that you do only one price change at a time. Price changes are not recommended for testing purposes.</p> <p>If you change a subscription price twice within a seven-day period, a user needs to agree only to the latest price change.</p> <p>If the price changes are more than seven days apart, the price changes do not cancel each other out. Instead, the user must agree to the first price change and have one renewal cycle at the first price. After the renewal cycle ends, you can then begin charging the second price. Renewals are then charged the second price each month.</p> <devsite-hats-survey hats-id="onAFgYxTD0kxBYCLVTd0Z41p75CM" listnr-id="5207477"></devsite-hats-survey> </div> <devsite-thumb-rating position="footer"> <template class="thumb-down-categories"> [{ "type": "thumb-down", "id": "missingTheInformationINeed", "label":"Missing the information I need" },{ "type": "thumb-down", "id": "tooComplicatedTooManySteps", "label":"Too complicated / too many steps" },{ "type": "thumb-down", "id": "outOfDate", "label":"Out of date" },{ "type": "thumb-down", "id": "samplesCodeIssue", "label":"Samples/Code issue" },{ "type": "thumb-down", "id": "otherDown", "label":"Other" }] </template> <template class="thumb-up-categories"> [{ "type": "thumb-up", "id": "easyToUnderstand", "label":"Easy to understand" },{ "type": "thumb-up", "id": "solvedMyProblem", "label":"Solved my problem" },{ "type": "thumb-up", "id": "otherUp", "label":"Other" }] </template> </devsite-thumb-rating> </article> <devsite-content-footer class="nocontent"> <p>Content and code samples on this page are subject to the licenses described in the <a href="/web/20210507003611/https://developer.android.com/license">Content License</a>. Java is a registered trademark of Oracle and/or its affiliates.</p> <p>Last updated 2021-03-23 UTC.</p> </devsite-content-footer> </devsite-content> </main> <devsite-footer-promos class="devsite-footer"> <nav class="devsite-footer-promos nocontent" aria-label="Promotions"> <ul class="devsite-footer-promos-list"> <li class="devsite-footer-promo"> <a href="//web.archive.org/web/20210507003611/https://twitter.com/AndroidDev" class="devsite-footer-promo-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Twitter Promo"> <img class="devsite-footer-promo-icon" src="/web/20210507003611im_/https://developer.android.com/_static/android/images/logo-twitter.svg" loading="lazy" alt="Twitter"> Twitter </a> <div class="devsite-footer-promo-description">Follow @AndroidDev on Twitter</div> </li> <li class="devsite-footer-promo"> <a href="//web.archive.org/web/20210507003611/https://www.youtube.com/user/androiddevelopers" class="devsite-footer-promo-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer YouTube Promo"> <img class="devsite-footer-promo-icon" src="//web.archive.org/web/20210507003611im_/https://www.gstatic.com/images/icons/material/product/2x/youtube_48dp.png" loading="lazy" alt="YouTube"> YouTube </a> <div class="devsite-footer-promo-description">Check out Android Developers on YouTube</div> </li> </ul> </nav> </devsite-footer-promos> <devsite-footer-linkboxes class="devsite-footer"> <nav class="devsite-footer-linkboxes nocontent" aria-label="Footer links"> <ul class="devsite-footer-linkboxes-list"> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">More Android</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//web.archive.org/web/20210507003611/https://www.android.com/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)"> Android </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//web.archive.org/web/20210507003611/https://www.android.com/enterprise/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)"> Enterprise </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//web.archive.org/web/20210507003611/https://www.android.com/security-center/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)"> Security </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//web.archive.org/web/20210507003611/https://source.android.com/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)"> Source </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Support</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//web.archive.org/web/20210507003611/https://issuetracker.google.com/issues/new?component=190923&amp;template=841312" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)"> Report platform bug </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//web.archive.org/web/20210507003611/https://issuetracker.google.com/issues/new?component=192697" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)"> Report documentation bug </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//web.archive.org/web/20210507003611/https://support.google.com/googleplay/android-developer" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)"> Google Play support </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://web.archive.org/web/20210507003611/https://google.qualtrics.com/jfe/form/SV_ewWXIoEVLBcyp7f??reserved=1&amp;utm_source=FooterLink&amp;Q_Language=en&amp;utm_medium=own_srch&amp;utm_campaign=developer.android.com&amp;utm_term=0&amp;utm_content=0&amp;productTag=reg&amp;campaignDate=may19&amp;pType=devel&amp;referral_code=gV420370" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)"> Join research studies </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Documentation</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="/web/20210507003611/https://developer.android.com/guide" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)"> Developer guides </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/web/20210507003611/https://developer.android.com/design" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)"> Design guides </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/web/20210507003611/https://developer.android.com/reference" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)"> API reference </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/web/20210507003611/https://developer.android.com/samples" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)"> Samples </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/web/20210507003611/https://developer.android.com/studio/intro" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)"> Android Studio </a> </li> </ul> </li> </ul> </nav> </devsite-footer-linkboxes> <devsite-footer-utility class="devsite-footer"> <div class="devsite-footer-utility nocontent"> <nav class="devsite-footer-sites" aria-label="Other Google Developers websites"> <a href="https://web.archive.org/web/20210507003611/https://developers.google.com/" class="devsite-footer-sites-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Developers Link"> <img class="devsite-footer-sites-logo" src="https://web.archive.org/web/20210507003611im_/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android/images/lockup-developers.svg" loading="lazy" alt="Google Developers"> </a> <ul class="devsite-footer-sites-list"> <li class="devsite-footer-sites-item"> <a href="//web.archive.org/web/20210507003611/https://developer.android.com/" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Android Link"> Android </a> </li> <li class="devsite-footer-sites-item"> <a href="//web.archive.org/web/20210507003611/https://developer.chrome.com/home" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Chrome Link"> Chrome </a> </li> <li class="devsite-footer-sites-item"> <a href="//web.archive.org/web/20210507003611/https://firebase.google.com/" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Firebase Link"> Firebase </a> </li> <li class="devsite-footer-sites-item"> <a href="//web.archive.org/web/20210507003611/https://cloud.google.com/" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Cloud Platform Link"> Google Cloud Platform </a> </li> <li class="devsite-footer-sites-item"> <a href="//web.archive.org/web/20210507003611/https://developers.google.com/products/" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer All products Link"> All products </a> </li> </ul> </nav> <nav class="devsite-footer-utility-links" aria-label="Utility links"> <ul class="devsite-footer-utility-list"> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//web.archive.org/web/20210507003611/https://policies.google.com/privacy" data-category="Site-Wide Custom Events" data-label="Footer Privacy link"> Privacy </a> </li> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="/web/20210507003611/https://developer.android.com/license" data-category="Site-Wide Custom Events" data-label="Footer License link"> License </a> </li> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="/web/20210507003611/https://developer.android.com/distribute/marketing-tools/brand-guidelines" data-category="Site-Wide Custom Events" data-label="Footer Brand guidelines link"> Brand guidelines </a> </li> <li class="devsite-footer-utility-item devsite-footer-utility-button"> <span class="devsite-footer-utility-description">Get news and tips by email</span> <a class="devsite-footer-utility-link gc-analytics-event" href="/web/20210507003611/https://developer.android.com/updates" data-category="Site-Wide Custom Events" data-label="Footer Subscribe link"> Subscribe </a> </li> </ul> <devsite-language-selector> <devsite-select class="devsite-language-selector-menu"> <select aria-label="Select your language preference." class="devsite-language-selector-select" name="language" track-name="click" track-type="languageSelector"> <option>Language</option> <option value="en" lang="en" track-metadata-original-language="en" track-metadata-selected-language="en" track-name="changed" track-type="languageSelector"> English </option> <option value="id" lang="id" track-metadata-original-language="en" track-metadata-selected-language="id" track-name="changed" track-type="languageSelector"> Bahasa Indonesia </option> <option value="es_419" lang="es_419" track-metadata-original-language="en" track-metadata-selected-language="es_419" track-name="changed" track-type="languageSelector"> Español – América Latina </option> <option value="pt_br" lang="pt_br" track-metadata-original-language="en" track-metadata-selected-language="pt_br" track-name="changed" track-type="languageSelector"> Português – Brasil </option> <option value="zh_cn" lang="zh_cn" track-metadata-original-language="en" track-metadata-selected-language="zh_cn" track-name="changed" track-type="languageSelector"> 中文 – 简体 </option> <option value="ja" lang="ja" track-metadata-original-language="en" track-metadata-selected-language="ja" track-name="changed" track-type="languageSelector"> 日本語 </option> <option value="ko" lang="ko" track-metadata-original-language="en" track-metadata-selected-language="ko" track-name="changed" track-type="languageSelector"> 한국어 </option> </select> </devsite-select> </devsite-language-selector> </nav> </div> </devsite-footer-utility> </section></section> <devsite-sitemask></devsite-sitemask> <devsite-snackbar></devsite-snackbar> <devsite-tooltip></devsite-tooltip> <devsite-heading-link></devsite-heading-link> <devsite-analytics enable-analytics-iframe> <script type="application/json" analytics>[{"gaid": "UA-5831155-1", "dimensions": {"dimension11": false, "dimension4": "Google Play's billing system", "dimension1": "Signed out", "dimension6": "en", "dimension3": false, "dimension5": "en"}, "metrics": {"ratings_value": "metric1", "ratings_count": "metric2"}}]</script> <script type="application/json" gtm>{"parameters": {"freeTrialEligibleUser": "False", "internalUser": "False", "language": {"machineTranslated": "False", "requested": "en", "served": "en"}, "pageType": "article", "projectName": "Google Play's billing system", "scriptsafe": null, "signedIn": "False", "tenant": "android", "recommendations": {"sourcePage": "", "sourceType": 0, "sourceRank": 0, "sourceIdenticalDescriptions": 0, "sourceTitleWords": 0, "sourceDescriptionWords": 0, "experiment": ""}}, "tags": ["GTM-KMSWPCJ"]}</script> </devsite-analytics> <devsite-badger></devsite-badger> <android-fully-clickable target=".fully-clickable"></android-fully-clickable> <script nonce="EBRXLESP2ddkfgvC0RrDSY9flkKVfZ"> (function(d,e,v,s,i,t,E){d['GoogleDevelopersObject']=i; t=e.createElement(v);t.async=1;t.src=s;E=e.getElementsByTagName(v)[0]; E.parentNode.insertBefore(t,E);})(window, document, 'script', 'https://web.archive.org/web/20210507003611/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android/js/app_loader.js', '[3,"en",null,"/js/devsite_app_module.js","https://web.archive.org/web/20210507003611/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e","https://web.archive.org/web/20210507003611/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android","https://web.archive.org/web/20210507003611/https://android-dot-devsite-v2-prod.appspot.com",null,null,["/_pwa/android/manifest.json","https://web.archive.org/web/20210507003611/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/images/video-placeholder.svg","https://web.archive.org/web/20210507003611/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android/images/favicon.png","https://web.archive.org/web/20210507003611/https://www.gstatic.com/devrel-devsite/prod/ve6010286661f973c8a44ecd021b66ac8957259bcceefb6c1b1428b622ca8a90e/android/images/lockup.svg","https://web.archive.org/web/20210507003611/https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700|Material+Icons"],1,null,[1,6,8,12,14,17,21,25,40,45,50,63,70,75,76,80,87,88,91,92,93,97,98,100,101,102,103,105,107,108,111,112,113,115,116,117,118,120,122,123,124,125,127,129,131,132,133,134,135,136],"AIzaSyAP-jjEJBzmIyKR4F-3XITp8yM9T1gEEI8","AIzaSyB6xiKGDR5O3Ak2okS4rLkauxGUG7XP0hg"]') </script> <devsite-a11y-announce></devsite-a11y-announce> </body> </html><!-- FILE ARCHIVED ON 00:36:11 May 07, 2021 AND RETRIEVED FROM THE INTERNET ARCHIVE ON 01:57:53 Dec 01, 2024. JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE. ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C. SECTION 108(a)(3)). --> <!-- playback timings (ms): captures_list: 0.478 exclusion.robots: 0.027 exclusion.robots.policy: 0.015 esindex: 0.008 cdx.remote: 5.183 LoadShardBlock: 1162.341 (3) PetaboxLoader3.resolve: 1146.128 (3) PetaboxLoader3.datanode: 92.846 (5) load_resource: 92.929 loaddict: 23.15 -->

Pages: 1 2 3 4 5 6 7 8 9 10