সাবস্ক্রিপশন জীবনচক্র

স্বয়ংক্রিয় নবায়নের আচরণ, পেমেন্ট প্রত্যাখ্যানের পরিস্থিতি এবং ডেভেলপারের ব্যবস্থাপনাগত পদক্ষেপসহ বিভিন্ন কারণের উপর নির্ভর করে, সাবস্ক্রিপশন ক্রয় তার জীবনচক্র জুড়ে নানা অবস্থার মধ্য দিয়ে যেতে পারে।

স্বয়ংক্রিয়ভাবে নবায়নযোগ্য সাবস্ক্রিপশনের জীবনচক্র পরিচালনা করুন

যখন কোনো ব্যবহারকারীর সাবস্ক্রিপশন অবস্থার পরিবর্তন হয়, তখন আপনার ব্যাকএন্ড সার্ভার একটি SubscriptionNotification বার্তা পায়।

সাবস-অটো-রিনিউ-স্টেট
চিত্র ১. স্বয়ংক্রিয়ভাবে নবায়নযোগ্য সাবস্ক্রিপশন ক্রয়ের জীবনচক্রের অবস্থা এবং রূপান্তর ঘটনাসমূহ।

আপনার ব্যাকএন্ডে স্টেট আপডেট করতে, নোটিফিকেশনে অন্তর্ভুক্ত পারচেজ টোকেনটি ব্যবহার করে purchases.subscriptionsv2.get API-টি কল করুন। এই এন্ডপয়েন্টটি একটি পারচেজ টোকেনের ভিত্তিতে সাবস্ক্রিপশনের সর্বশেষ স্টেট প্রদান করে এবং সাবস্ক্রিপশন ব্যবস্থাপনার জন্য এটিকে নির্ভরযোগ্য উৎস হিসেবে বিবেচনা করা হয়।

সাবস্ক্রিপশন সাইনআপের সময় থেকে মেয়াদ শেষ হওয়ার পর ৬০ দিন পর্যন্ত পারচেজ টোকেনটি বৈধ থাকে। এই তারিখের পর, গুগল প্লে ডেভেলপার এপিআই কল করার জন্য পারচেজ টোকেনটি আর বৈধ থাকে না।

নতুন স্বয়ংক্রিয়ভাবে নবায়নযোগ্য সাবস্ক্রিপশন ক্রয়

When a user purchases a subscription, a SubscriptionNotification message with type SUBSCRIPTION_PURCHASED is sent to your RTDN client. Whether you receive this notification or you register a new purchase in-app through PurchasesUpdatedListener or manually fetching purchases in your app's onResume() method, you should process the new purchase in your secure backend. To do this, follow these steps:

  1. সর্বশেষ সাবস্ক্রিপশন অবস্থা ধারণকারী একটি সাবস্ক্রিপশন রিসোর্স পেতে purchases.subscriptionsv2.get এন্ডপয়েন্টটি কোয়েরি করুন।
  2. নিশ্চিত করুন যে subscriptionState ফিল্ডের মান SUBSCRIPTION_STATE_ACTIVE হয়।
  3. ক্রয়টি যাচাই করুন
  4. ব্যবহারকারীকে কন্টেন্টে অ্যাক্সেস দিন। ক্রয়ের সাথে যুক্ত ব্যবহারকারী অ্যাকাউন্টটি সাবস্ক্রিপশন রিসোর্সের ExternalAccountIdentifiers অবজেক্টের মাধ্যমে শনাক্ত করা যেতে পারে, যদি ক্রয়ের সময় setObfuscatedAccountId এবং setObfuscatedProfileId ব্যবহার করে আইডেন্টিফায়ার সেট করা হয়ে থাকে।

SubscriptionPurchaseLineItem এর offerPhase ফিল্ডটি সাবস্ক্রিপশনের বর্তমান পর্যায়, যেমন ফ্রি ট্রায়াল বা প্রারম্ভিক মূল্য সম্পর্কে বিস্তারিত তথ্য প্রদান করে।

প্লে বিলিং লাইব্রেরিতে একটি সাবস্ক্রিপশন স্বীকার করার জন্য acknowledgePurchase() মেথড এবং স্বীকৃতির অবস্থা পরীক্ষা করার জন্য isAcknowledged() মেথডও রয়েছে। তবে, উন্নততর নিরাপত্তার জন্য আমরা আপনাকে আপনার ব্যাকএন্ডে ক্রয় প্রক্রিয়াকরণ পরিচালনা করার পরামর্শ দিই।

নতুন ক্রয়ের জন্য সাবস্ক্রিপশন রিসোর্সটি নিম্নলিখিত উদাহরণের মতো দেখতে হয়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  "startTime": "2022-04-22T18:39:58.270Z",
  "regionCode": "US",
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "latestOrderId": "GPA.3333-4137-0319-36762",
  "acknowledgementState": "ACKNOWLEDGEMENT_STATE_PENDING", // need to acknowledge new purchases
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      },
      "offerPhase": {
        "freeTrial": {}
      }
    }
  ],
}

সাবস্ক্রিপশন পুনর্নবীকরণ

কিস্তিবিহীন, স্বয়ংক্রিয়ভাবে নবায়নযোগ্য সাবস্ক্রিপশনের ক্ষেত্রে, সাবস্ক্রিপশন নবায়ন হলে একটি SUBSCRIPTION_RENEWED নোটিফিকেশন পাঠানো হয়। কিস্তিভিত্তিক সাবস্ক্রিপশনের ক্ষেত্রে, প্রতিবার বিলিং তারিখে সাবস্ক্রিপশনের চার্জ কাটার সময় একটি SUBSCRIPTION_RENEWED নোটিফিকেশন পাঠানো হয়। নিশ্চিত করুন যে ব্যবহারকারী এখনও সাবস্ক্রিপশনটির জন্য যোগ্য আছেন এবং তারপর Google Play Developer API থেকে প্রাপ্ত সাবস্ক্রিপশন রিসোর্সে দেওয়া নতুন expiryTime দিয়ে সাবস্ক্রিপশনের স্টেট আপডেট করুন। সাবস্ক্রিপশন রিসোর্সটি দেখতে নিচের উদাহরণের মতো:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  "startTime": "2022-04-22T18:39:58.270Z",
  "regionCode": "US",
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "latestOrderId": "GPA.3333-4137-0319-36762",
  "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      },
      "offerPhase": {
        "basePrice": {}
      }
    }
  ]
}

সাবস্ক্রিপশন নবায়নের বিষয়টি আপনাকে স্বীকার করার প্রয়োজন নেই।

অনুগ্রহের সময়কাল

সাবস্ক্রিপশন নবায়নের ক্ষেত্রে অর্থপ্রদানে কোনো সমস্যা হলে, গুগল ব্যবহারকারীকে অবহিত করে এবং সাবস্ক্রিপশনের মেয়াদ শেষ হওয়ার আগে কিছু সময়ের জন্য পর্যায়ক্রমে তা নবায়ন করার চেষ্টা করে। এই পুনরুদ্ধার সময়কালে একটি গ্রেস পিরিয়ড এবং তার পরে একটি অ্যাকাউন্ট হোল্ড পিরিয়ড থাকতে পারে। গ্রেস পিরিয়ড চলাকালীন, ব্যবহারকারীর তার সাবস্ক্রিপশনের সুবিধাগুলো ব্যবহারের সুযোগ থাকা উচিত।

` queryPurchasesAsync() ` মেথডটি গ্রেস পিরিয়ডে থাকা পারচেজগুলো রিটার্ন করতে থাকে। যদি আপনার অ্যাপ কোনো ব্যবহারকারী একটি সাবস্ক্রিপশনের জন্য যোগ্য কিনা তা পরীক্ষা করার জন্য শুধুমাত্র queryPurchasesAsync এর উপর নির্ভর করে, তাহলে আপনার অ্যাপের গ্রেস পিরিয়ডগুলো স্বয়ংক্রিয়ভাবে পরিচালনা করা উচিত, কারণ এই সাবস্ক্রিপশনগুলো প্লে বিলিং লাইব্রেরির মাধ্যমে সক্রিয় হিসাবে দেখানো হয়।

আপনার ব্যাকএন্ডের সাথে সাবস্ক্রিপশনের অবস্থা সিঙ্ক্রোনাইজ করলে আপনি পেমেন্ট প্রত্যাখ্যান সম্পর্কে আরও সচেতন হতে পারবেন এবং অনিচ্ছাকৃত গ্রাহক হারানো কমানোর চেষ্টা করার সময় আরও প্রাসঙ্গিক তথ্য পাবেন। ব্যবহারকারী যখন গ্রেস পিরিয়ডে প্রবেশ করে তখন বিজ্ঞপ্তি পেতে SUBSCRIPTION_IN_GRACE_PERIOD টাইপের SubscriptionNotification মেসেজের জন্য লিসেন করুন। ব্যবহারকারী যখন গ্রেস পিরিয়ডে থাকে, তখন সাবস্ক্রিপশন রিসোর্সে autoRenewEnabled = true থাকে। গ্রেস পিরিয়ড শেষ না হওয়া পর্যন্ত Google Play ডাইনামিকভাবে expiryTime ভ্যালুটি বাড়িয়ে দেয়, কারণ ব্যবহারকারী বাতিল না করা পর্যন্ত বা গ্রেস পিরিয়ড তার সর্বোচ্চ মেয়াদ পর্যন্ত স্থায়ী না হওয়া পর্যন্ত এনটাইটেলমেন্ট স্থায়ী থাকা উচিত। এই সময়কালে subscriptionState ফিল্ডের ভ্যালু হলো SUBSCRIPTION_STATE_IN_GRACE_PERIOD । সাবস্ক্রিপশন রিসোর্সটি নিম্নলিখিত উদাহরণের মতো দেখায়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_IN_GRACE_PERIOD",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_future,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      }
    }
  ],
}

প্লে স্টোর গ্রেস পিরিয়ডে থাকা ব্যবহারকারীদের জানায় যে তাদের পেমেন্ট প্রত্যাখ্যান করা হয়েছে এবং প্লে স্টোরে তাদের পেমেন্ট পদ্ধতির সমস্যাগুলো সমাধান করার জন্য অনুরোধ করে। যখন কোনো ব্যবহারকারী গ্রেস পিরিয়ডে প্রবেশ করেন, তখন ব্যর্থতাটি অনিচ্ছাকৃত হয়ে থাকলে, ব্যবহারকারীকে তাদের পেমেন্ট পদ্ধতি ঠিক করার জন্য উৎসাহিত করা উচিত। এটি করার একটি সহজ উপায় হলো ইন-অ্যাপ মেসেজিং এপিআই (In-App Messaging API) ব্যবহার করা। ব্যবহারকারী যখন আপনার অ্যাপটি খোলেন, তখন যদি আপনি এই এপিআই-টি কল করেন, তবে একটি অস্থায়ী স্নাকবারে তাদের একটি প্লে মেসেজ দেখানো হয়, যা ব্যবহারকারীকে জানায় যে তাদের পেমেন্ট প্রত্যাখ্যান করা হয়েছে। এই মেসেজটিতে ব্যবহারকারীর জন্য গুগল প্লে-তে তাদের পেমেন্ট পদ্ধতি ঠিক করার একটি ডিপ লিঙ্কও থাকে।

ব্যবহারকারী তার পেমেন্ট পদ্ধতি ঠিক করার সাথে সাথেই সাবস্ক্রিপশনটি তার আসল নবায়নের তারিখে নবায়ন হয়ে যায়, এবং আপনি 'নবায়ন' অংশে বর্ণিত পদ্ধতি অনুযায়ী নবায়নটি সম্পন্ন করতে পারেন।

যদি ব্যবহারকারী নির্ধারিত সময়ের মধ্যে তাদের অর্থপ্রদানের পদ্ধতি ঠিক না করেন, তাহলে সাবস্ক্রিপশনটি অ্যাকাউন্ট হোল্ডে চলে যায় এবং তারা তাদের অধিকার হারান।

গ্রেস পিরিয়ড অ্যাক্সেস এবং পুনরুদ্ধার

চিত্র ২-এ এমন একটি সাবস্ক্রিপশনের টাইমলাইন দেখানো হয়েছে, যা একটি গ্রেস পিরিয়ডে প্রবেশ করে এবং ব্যবহারকারী তার পেমেন্ট পদ্ধতি ঠিক করলে তা পুনরায় চালু হয়। গ্রেস পিরিয়ড শেষ হওয়ার পর, ব্যবহারকারী সাবস্ক্রিপশনের সুবিধাগুলো হারাবেন এবং তার অ্যাকাউন্ট হোল্ডে চলে যাবে।

চিত্র ২. এমন একটি সাবস্ক্রিপশনের সময়রেখা যা গ্রেস পিরিয়ডে প্রবেশ করে এবং এর মেয়াদ শেষ হওয়ার আগেই পুনরুদ্ধার হয়।

নিম্নলিখিত বিষয়গুলো মনে রাখা গুরুত্বপূর্ণ:

  • গ্রেস পিরিয়ড চলাকালীন, ব্যবহারকারী সাবস্ক্রিপশনের সুবিধাগুলো ব্যবহারের সুযোগ পাবেন।
  • গ্রেস পিরিয়ডের মধ্যে কোনো সাবস্ক্রিপশন পুনরুদ্ধার হলে, নবায়নের তারিখ পুনরায় সেট হয় না
  • আপনি যদি গ্রেস পিরিয়ড পরিবর্তন করেন, তাহলে যে ব্যবহারকারীরা বর্তমানে গ্রেস পিরিয়ডের মধ্যে আছেন, তাদের উপর এর কোনো প্রভাব পড়বে না। পরিবর্তনের পর যেসব সাবস্ক্রিপশন রিনিউয়াল গ্রেস পিরিয়ডে প্রবেশ করবে, সেগুলোর ক্ষেত্রে নতুন গ্রেস পিরিয়ডটি প্রতিফলিত হবে। উদাহরণস্বরূপ, আপনি যদি গ্রেস পিরিয়ড ৭ দিন থেকে বাড়িয়ে ১৪ দিন করেন, তাহলে পরিবর্তনের পর যেসব ব্যবহারকারী গ্রেস পিরিয়ডে প্রবেশ করবেন, তারা নতুন ১৪-দিনের গ্রেস পিরিয়ডটি পাবেন।
  • সাবস্ক্রিপশনটি সক্রিয় অবস্থায় থাকবে এবং সাইলেন্ট গ্রেস পিরিয়ড শেষ না হওয়া পর্যন্ত আপনি কোনো গ্রেস পিরিয়ড RTDN পাবেন না।

নীরব অবকাশকাল

আপনি ০ দিনের একটি গ্রেস পিরিয়ড সেট করতে পারেন, কিন্তু পেমেন্ট পুনরায় চেষ্টা করার জন্য পর্যাপ্ত সময় নিশ্চিত করতে প্লে ন্যূনতম ১ দিন অপেক্ষা করবে। এই নীরব গ্রেস পিরিয়ডটি পেমেন্ট প্রক্রিয়াকরণের জন্য একটি সুরক্ষা ব্যবস্থা হিসেবে কাজ করে। এই ২৪-ঘণ্টার সময়কালে সাবস্ক্রিপশনটি ACTIVE অবস্থায় থাকে।

সাবস্ক্রিপশনের অবস্থার পরিবর্তন সম্পর্কে অবগত থাকার সর্বোত্তম উপায় হলো রিয়েল-টাইম ডেভেলপার নোটিফিকেশন (RTDN) শোনা এবং সে অনুযায়ী ব্যবস্থা নেওয়া। সাবস্ক্রিপশনের আরও সঠিক অবস্থা জানতে, মেয়াদ শেষ হওয়ার সময়ের পরিবর্তে RTDN সময়ে purchases.subscriptionsv2.get() মেথডটি কল করুন।

২৪-ঘণ্টার নীরব সময়সীমা শেষে সাবস্ক্রিপশনের অবস্থার উপর নির্ভর করে আপনি নিম্নলিখিত বিজ্ঞপ্তিগুলির মধ্যে একটি পাবেন:

  • SUBSCRIPTION_ON_HOLD (যদি সক্রিয় থাকে)
  • SUBSCRIPTION_CANCELED (যদি বাতিল করা হয়)
  • SUBSCRIPTION_EXPIRED (যদি মেয়াদোত্তীর্ণ হয়ে থাকে)
  • SUBSCRIPTION_RENEWED (যদি সফলভাবে নবায়ন করা হয়ে থাকে)

২৪-ঘণ্টার নীরব সময়সীমা শেষ হওয়ার পরেও যেকোনো সময়ে সাবস্ক্রিপশনের সর্বশেষ অবস্থা জানতে আপনি subscriptionV2.get() মেথডটি কল করতে পারেন।

অ্যাকাউন্ট হোল্ড

সাবস্ক্রিপশন নবায়নের ক্ষেত্রে অর্থপ্রদানে সমস্যা হলে, যেকোনো গ্রেস পিরিয়ড শেষ হওয়ার পর একটি অ্যাকাউন্ট হোল্ড পিরিয়ড শুরু হয়। যখন কোনো সাবস্ক্রিপশন অ্যাকাউন্ট হোল্ডে চলে যায়, তখন আপনার উচিত সাবস্ক্রিপশন এনটাইটেলমেন্টে অ্যাক্সেস ব্লক করে দেওয়া।

অ্যাকাউন্ট হোল্ড চলাকালীন, প্রয়োজন অনুযায়ী আপনার সাবস্ক্রিপশন বাতিল , পুনরুদ্ধার বা পুনরায় কেনার কাজগুলো চালিয়ে যাওয়া উচিত, কারণ সাবস্ক্রিপশন হোল্ডে থাকা অবস্থায় ব্যবহারকারী এই পরিবর্তনগুলো করতে পারেন।

ব্যবহারকারী যখন অ্যাকাউন্ট হোল্ড পিরিয়ডে প্রবেশ করেন, তখন RTDN আপনাকে অবহিত করে, যাতে আপনি যত তাড়াতাড়ি সম্ভব তাদের জানাতে পারেন যে কেন তাদের সাবস্ক্রিপশনে অ্যাক্সেস স্থগিত করা হয়েছে। এটি করার একটি সহজ উপায় হলো ইন-অ্যাপ মেসেজিং এপিআই (In-App Messaging API) ব্যবহার করা। আপনার ব্যবহারকারী যখন অ্যাপটি খুলবেন, তখন এই এপিআই কল করলে একটি অস্থায়ী স্নাকবারে ব্যবহারকারীকে একটি বার্তা দেখানো হবে, যা তাদের জানাবে যে তাদের পেমেন্ট প্রত্যাখ্যান করা হয়েছে। এই বার্তায় একটি ডিপ লিঙ্কও থাকে, যার মাধ্যমে ব্যবহারকারী গুগল প্লে-তে তাদের পেমেন্ট পদ্ধতি ঠিক করতে পারেন।

যদি আপনার ব্যবহারকারীরা আপনার অ্যাপের বাইরেও সাবস্ক্রিপশনের কন্টেন্ট অ্যাক্সেস করতে পারেন, তাহলে তারা হয়তো দেখতে পারেন যে বিভিন্ন প্ল্যাটফর্মে তারা অ্যাক্সেস হারিয়ে ফেলেছেন। পেমেন্ট প্রত্যাখ্যান হওয়ার কারণে তাদের সাবস্ক্রিপশনটি আর সক্রিয় নেই, এই বিষয়টি জানানোর জন্য আপনি ব্যবহারকারীকে একটি পুশ নোটিফিকেশন বা ইমেল পাঠাতে পারেন।

অ্যাকাউন্ট হোল্ড চলাকালীন ` queryPurchasesAsync() ` মেথডটি সাবস্ক্রিপশনটি রিটার্ন করে না, তাই আপনার অ্যাপ যদি বিদ্যমান কেনাকাটাগুলো দেখানোর জন্য এই মেথডটির ওপর নির্ভর করে, তবে আপনার ডিফল্টভাবে অ্যাকাউন্ট হোল্ড সাপোর্ট করা উচিত।

রিয়েল-টাইম ডেভেলপার নোটিফিকেশনের মাধ্যমে, যখন কোনো সাবস্ক্রিপশন অ্যাকাউন্ট হোল্ডে যায়, তখন আপনি SUBSCRIPTION_ON_HOLD টাইপের একটি SubscriptionNotification মেসেজ পান। নতুন সাবস্ক্রিপশনের তথ্য পুনরুদ্ধার করতে আপনার সুরক্ষিত ব্যাকএন্ড সার্ভার থেকে purchases.subscriptionsv2.get মেথডটি কল করুন। অ্যাকাউন্ট হোল্ড চলাকালীন , সাবস্ক্রিপশন রিসোর্সের expiryTime ফিল্ডটি একটি অতীত টাইমস্ট্যাম্পে সেট করা হয় এবং subscriptionState ফিল্ডটি SUBSCRIPTION_STATE_ON_HOLD এ সেট করা হয়।

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ON_HOLD",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_past,
      ...
    }
  ],
}

অ্যাক্সেস পুনরুদ্ধার করতে, ব্যবহারকারীদের অবশ্যই তাদের পেমেন্ট পদ্ধতি ঠিক করতে হবে। প্লে অ্যাকাউন্ট হোল্ডে থাকা ব্যবহারকারীদের পেমেন্ট প্রত্যাখ্যানের বিষয়ে অবহিত করে, এবং আপনারও উচিত তাদের পেমেন্ট পদ্ধতি ঠিক করতে উৎসাহিত করা।

ব্যবহারকারী তার পেমেন্ট পদ্ধতি ঠিক করার পর, সাবস্ক্রিপশনটি আবার সক্রিয় অবস্থায় ফিরে আসে এবং আপনাকে অবশ্যই সাবস্ক্রাইব করা কন্টেন্টে অ্যাক্সেস পুনরুদ্ধার করতে হবে। এই ক্ষেত্রে, পারচেজ টোকেনটি অ্যাকাউন্ট হোল্ড শুরু হওয়ার আগের মতোই থাকে, কারণ একই পারচেজটি পুনরুদ্ধার হচ্ছে, এবং আপনি SUBSCRIPTION_RECOVERED টাইপের একটি RTDN পাবেন।

কিস্তিভিত্তিক সাবস্ক্রিপশনের ক্ষেত্রে, যেকোনো একটি পেমেন্টের চেষ্টাতেই অর্থপ্রদান প্রত্যাখ্যাত বা পুনরুদ্ধার হতে পারে।

পুনরুদ্ধারের পরে, প্লে বিলিং লাইব্রেরি queryPurchasesAsync() পদ্ধতির মাধ্যমে সাবস্ক্রিপশনটি আবার ফেরত দেয়। যদি আপনি কোনো ব্যবহারকারী একটি সাবস্ক্রিপশনের অধিকারী কিনা তা নির্ধারণ করতে এই পদ্ধতিটি ব্যবহার করেন, তাহলে আপনার অ্যাপের উচিত অ্যাকাউন্ট হোল্ড থেকে সাবস্ক্রিপশনটি পুনরুদ্ধারের বিষয়টি স্বয়ংক্রিয়ভাবে পরিচালনা করা।

যখন কোনো সাবস্ক্রিপশন পুনরুদ্ধার করা হয় এবং ব্যবহারকারী পুনরায় অ্যাক্সেস ফিরে পাবেন, তখন বিজ্ঞপ্তি পেতে SUBSCRIPTION_RECOVERED টাইপের একটি SubscriptionNotification মেসেজের জন্য অপেক্ষা করুন। এই বিজ্ঞপ্তিটি পাওয়ার পর আপনি যদি কোনো সাবস্ক্রিপশনের জন্য কোয়েরি করেন, তাহলে expiryTime ফিল্ডটি ভবিষ্যতের একটি টাইমস্ট্যাম্পে সেট করা হয় এবং subscriptionState ফিল্ডটি আবার SUBSCRIPTION_STATE_ACTIVE এ সেট হয়ে যায়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      ...
    }
  ],
}

যদি ব্যবহারকারী অ্যাকাউন্ট হোল্ড পিরিয়ড শেষ হওয়ার আগে তাদের পেমেন্ট পদ্ধতি ঠিক না করেন, তাহলে আপনি SUBSCRIPTION_CANCELED টাইপের একটি RTDN পাবেন। বাতিলকরণ কীভাবে পরিচালনা করতে হয় তার নির্দেশাবলীর জন্য, ' বাতিলকরণ' (Cancellations) দেখুন। যখন আপনি এইভাবে বাতিল করা কোনো সাবস্ক্রিপশনের জন্য কোয়েরি করেন, তখন ফেরত আসা expiryTime ফিল্ডটি একটি অতীত টাইমস্ট্যাম্পে সেট করা হয়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_CANCELED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_past,
      ...
    }
  ],
}

অ্যাকাউন্ট হোল্ড চলাকালীন বাতিলের বিজ্ঞপ্তি পাওয়ার সাথে সাথেই, আপনি SUBSCRIPTION_EXPIRED টাইপের একটি RTDN-ও পাবেন, কারণ ব্যবহারকারীর পরিশোধিত প্রাপ্যতা শেষ হয়ে গেছে এবং বাতিলের সাথে সাথে সাবস্ক্রিপশনটিও বাতিল হয়ে গেছে। আপনি এই মেয়াদোত্তীর্ণ হওয়া বিষয়টি স্বাভাবিকভাবেই সামলাতে পারবেন।

ব্যবহারকারী তার মূল ক্রয়ের পর থেকে অ্যাকাউন্ট স্থগিত থাকার সময়কালে অ্যাপের মাধ্যমে একই সাবস্ক্রিপশন প্ল্যান বা আপনার দেওয়া অন্য কোনো প্ল্যান পুনরায় কিনে আবার অ্যাক্সেস ফিরে পেতে পারেন। সেক্ষেত্রে, একটি নতুন পারচেজ টোকেন ইস্যু করা হয় এবং এই নতুন ইনস্ট্যান্সটিকে প্রতিনিধিত্বকারী SUBSCRIPTION_PURCHASED ইভেন্টের অংশ হিসেবে নতুন মানটি ফেরত দেওয়া হয়।

অ্যাকাউন্ট হোল্ড অ্যাক্সেস এবং পুনরুদ্ধার

চিত্র ৩-এ এমন একটি সাবস্ক্রিপশনের টাইমলাইন দেখানো হয়েছে, যা অ্যাকাউন্ট হোল্ডে চলে যায় এবং ব্যবহারকারী তার পেমেন্ট পদ্ধতি ঠিক করার পর পুনরুদ্ধার হয়।

চিত্র ৩. এমন একটি সাবস্ক্রিপশনের সময়রেখা যা অ্যাকাউন্ট হোল্ডে চলে যায় এবং মেয়াদ শেষ হওয়ার আগেই পুনরুদ্ধার হয়।

পূর্ববর্তী উদাহরণের মতোই, চিত্র ৪-এ এমন একটি সাবস্ক্রিপশনের টাইমলাইন দেখানো হয়েছে যা অ্যাকাউন্ট হোল্ডে যাওয়ার আগে প্রথমে একটি গ্রেস পিরিয়ডে প্রবেশ করে এবং তারপর হোল্ডে থাকা অবস্থাতেই পুনরুদ্ধার হয়।

চিত্র ৪। এমন একটি সাবস্ক্রিপশনের সময়রেখা যা গ্রেস পিরিয়ডে প্রবেশ করে, তারপর অ্যাকাউন্ট হোল্ডে চলে যায় এবং অবশেষে হোল্ডের মেয়াদ শেষ হওয়ার আগেই পুনরুদ্ধার হয়।

নিম্নলিখিত বিষয়গুলো মনে রাখা গুরুত্বপূর্ণ:

  • কোনো সাবস্ক্রিপশন অ্যাকাউন্ট হোল্ডে যাওয়ার আগে, গুগল প্লে সর্বোচ্চ ৪৮ ঘণ্টা পর্যন্ত পেমেন্ট পদ্ধতি থেকে টাকা কেটে নেওয়ার জন্য অতিরিক্ত চেষ্টা করে। এই সময়কালে ব্যবহারকারী সাবস্ক্রিপশনের সুবিধাগুলো উপভোগ করতে পারেন। এই পুনঃচেষ্টার সময়সীমা শেষ হয়ে গেলে, সাবস্ক্রিপশনটি অ্যাকাউন্ট হোল্ডে চলে যায় এবং ব্যবহারকারী সাবস্ক্রিপশনের সুবিধাগুলো ব্যবহারের সুযোগ হারান।
  • কোনো পেমেন্ট পদ্ধতি ব্যর্থ হওয়ার কারণে সাবস্ক্রিপশনটি পজ বা স্থগিত অবস্থা থেকে পুনরায় চালু করা হলে, সেটি সরাসরি অ্যাকাউন্ট হোল্ডে চলে যায়।
  • যখন কোনো সাবস্ক্রিপশন অ্যাকাউন্ট হোল্ড থেকে পুনরুদ্ধার হয়, তখন নবায়নের তারিখটি পুনরায় সেট হয়।

মেয়াদ শেষ

সাবস্ক্রিপশনের মেয়াদ শেষ হয়ে গেলে, ব্যবহারকারীর সেই সাবস্ক্রিপশনে অ্যাক্সেস চলে যাওয়া উচিত। সেক্ষেত্রে SUBSCRIPTION_EXPIRED টাইপের একটি SubscriptionNotification মেসেজ পাঠানো হয়। আপনি যখন এই নোটিফিকেশনটি পাবেন, তখন সর্বশেষ সাবস্ক্রিপশন রিসোর্সটি পেতে Google Play Developer API-কে কোয়েরি করুন। subscriptionState যে SUBSCRIPTION_STATE_EXPIRED তা নিশ্চিত করার পর, আপনার ব্যাকএন্ডে এনটাইটেলমেন্টটি সরিয়ে দিন এবং পারচেজ স্টেটটিকে ইনভ্যালিড হিসেবে রেজিস্টার করুন। সাবস্ক্রিপশন রিসোর্সটি দেখতে নিচের উদাহরণের মতো হয়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_EXPIRED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": expiration_time_in_past,
      ...
    }
  ],
}

বাতিলকরণ

একজন ব্যবহারকারী প্লে সাবস্ক্রিপশন সেন্টার থেকে স্বেচ্ছায় একটি সাবস্ক্রিপশন বাতিল করতে পারেন অথবা অ্যাকাউন্ট হোল্ডে থাকার পর যদি তিনি তা পুনরুদ্ধার না করেন, তবে তার সাবস্ক্রিপশনটি স্বয়ংক্রিয়ভাবে বাতিল হয়ে যেতে পারে। ডেভেলপাররাও purchases.subscriptionsv2.cancel ব্যবহার করে বাতিলকরণ প্রক্রিয়া শুরু করতে পারেন। যখন একটি সাবস্ক্রিপশন বাতিল করা হয়, তখন ব্যবহারকারী বর্তমান বিলিং চক্রের শেষ পর্যন্ত কন্টেন্ট ব্যবহারের সুযোগ পান। বিলিং চক্র শেষ হলে, সেই সুযোগ প্রত্যাহার করা উচিত।

কিস্তিবিহীন, স্বয়ংক্রিয়ভাবে নবায়নযোগ্য কোনো সাবস্ক্রিপশন বাতিল করলে একটি SUBSCRIPTION_CANCELED নোটিফিকেশন আসে। আপনি যখন এই নোটিফিকেশনটি পান, তখন Google Play Developer API থেকে প্রাপ্ত সাবস্ক্রিপশন রিসোর্সের subscriptionState ফিল্ডটি SUBSCRIPTION_STATE_CANCELED এ সেট করা থাকে এবং expiryTime ফিল্ডে সেই তারিখটি থাকে যেদিন ব্যবহারকারী সাবস্ক্রিপশনটির অ্যাক্সেস হারাবেন। যদি সেই তারিখটি অতীতের হয়, তাহলে ব্যবহারকারী অবিলম্বে তার অধিকার হারাবেন। উদাহরণস্বরূপ, পেমেন্ট প্রত্যাখ্যানের কারণে অ্যাকাউন্ট হোল্ডে থাকা অবস্থায় কোনো ব্যবহারকারী সাবস্ক্রিপশন বাতিল করলে এমনটা হতে পারে।

বাতিল করা ক্রয়ের সাবস্ক্রিপশন রিসোর্সটি নিম্নলিখিত উদাহরণের মতো দেখতে হয়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_CANCELED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": expiration_time,
      ...
    }
  ],
}

কিস্তিভিত্তিক সাবস্ক্রিপশনের ক্ষেত্রে, প্রতিশ্রুতি মেয়াদের জন্য পেমেন্ট বাকি থাকা অবস্থায় ব্যবহারকারীর পক্ষ থেকে বাতিলের উদ্যোগ নেওয়া হলে একটি SUBSCRIPTION_CANCELLATION_SCHEDULED নোটিফিকেশন পাঠানো হয়। বাতিলকরণটি প্রক্রিয়াধীন থাকে এবং বর্তমান প্রতিশ্রুতি মেয়াদের শেষে কার্যকর হয়। আপনি যখন এই নোটিফিকেশনটি পান, তখন Google Play Developer API থেকে প্রাপ্ত সাবস্ক্রিপশন রিসোর্সের subscriptionState ফিল্ডটি SUBSCRIPTION_STATE_ACTIVE হিসেবে সেট করা থাকে, কারণ কিস্তিভিত্তিক সাবস্ক্রিপশনটি প্রতিশ্রুতি মেয়াদের শেষ পর্যন্ত সক্রিয় থাকে। তবে, সেখানে একটি খালি pendingCancellation অবজেক্ট উপস্থিত থাকে। একটি SUBSCRIPTION_CANCELED নোটিফিকেশন পাঠানো হয় এবং প্রতিশ্রুতি মেয়াদের শেষে একটি SUBSCRIPTION_EXPIRED নোটিফিকেশন পাঠানো হয়।

কিস্তিতে কেনা সাবস্ক্রিপশন বাতিলের অপেক্ষায় থাকা সাবস্ক্রিপশন রিসোর্সটি নিম্নলিখিত উদাহরণের মতো দেখতে হয়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_plan01",
      "expiryTime": expiration_time,
      "autoRenewingPlan": {
        "autoRenewEnabled": true,
        "recurringPrice": {
          "currencyCode": "USD",
          "units": "1",
          "nanos": 990000000
        },
        "installmentDetails": {
          "initialCommittedPaymentsCount": 6,
          "remainingCommittedPaymentsCount": 5,
          "pendingCancellation": {}
      ...
        }
      }
    }
  ],
}

সাবস্ক্রিপশনটি কেন বাতিল করা হয়েছিল তা জানতে (উদাহরণস্বরূপ, সাবস্ক্রিপশনটি ব্যবহারকারী, সিস্টেম, নাকি আপনি বাতিল করেছেন) আপনি সাবস্ক্রিপশন রিসোর্সের canceledStateContext ফিল্ডটি দেখতে পারেন। যদি সাবস্ক্রিপশনটি ব্যবহারকারী দ্বারা বাতিল করা হয়ে থাকে, তবে ব্যবহারকারী কেন সাবস্ক্রিপশনটি বাতিল করেছেন তা জানতে আপনি userInitiatedCancellation ফিল্ডটি দেখতে পারেন। এটি যোগাযোগ কৌশল নির্ধারণে সহায়ক হতে পারে।

যখন কোনো সাবস্ক্রিপশন বাতিল করা হয় কিন্তু তার মেয়াদ এখনো শেষ হয়নি, তখনও queryPurchasesAsync() থেকে সেটি ফেরত আসে। আপনি আপনার অ্যাপে একটি বার্তা প্রদর্শন করে ব্যবহারকারীকে জানাতে পারেন যে তার সাবস্ক্রিপশনটি বাতিল করা হয়েছে এবং মেয়াদ শেষ হওয়ার তারিখটিও জানিয়ে দিতে পারেন।

বাতিলকরণ

বিভিন্ন কারণে একটি সাবস্ক্রিপশন বাতিল করা হতে পারে, যার মধ্যে রয়েছে আপনার ব্যাকএন্ড কর্তৃক purchases.subscriptionsv2.revoke ব্যবহার করে সাবস্ক্রিপশন বাতিল করা অথবা ক্রয়ের অর্থ ফেরত দেওয়া। এই পরিস্থিতিতে, ব্যবহারকারীর অধিকার অবিলম্বে বাতিল করুন। যখন এটি ঘটে, তখন SUBSCRIPTION_REVOKED টাইপের একটি SubscriptionNotification বার্তা পাঠানো হয়। আপনি যখন এই বিজ্ঞপ্তিটি পান, তখন Google Play Developer API থেকে প্রাপ্ত সাবস্ক্রিপশন রিসোর্সের subscriptionState ফিল্ডটি SUBSCRIPTION_STATE_EXPIRED এ সেট করা থাকে।

বাতিল করা ক্রয়ের সাবস্ক্রিপশন রিসোর্সটি নিম্নলিখিত উদাহরণের মতো দেখতে হয়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_EXPIRED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": expiration_time,
      ...
    }
  ]
}

স্থগিত সাবস্ক্রিপশন

বিভিন্ন কারণে আপনি একজন ব্যবহারকারীর অধিকার বাড়াতে চাইতে পারেন। উদাহরণস্বরূপ, আপনি একটি বিশেষ প্রচারমূলক অফার হিসেবে ব্যবহারকারীদের বিনামূল্যে প্রবেশাধিকার দিতে পারেন, যেমন একটি সিনেমা কেনার জন্য এক সপ্তাহ বিনামূল্যে দেওয়া, অথবা সদিচ্ছার নিদর্শন হিসেবে গ্রাহকদের বিনামূল্যে প্রবেশাধিকার প্রদান করা।

আপনি সাবস্ক্রিপশনের (অ্যাড-অন সহ সাবস্ক্রিপশন সহ) বিলিং তারিখ স্থগিত করতে purchases.subscriptionsv2.defer API ব্যবহার করতে পারেন। যখন আপনি অ্যাড-অন সহ একটি সাবস্ক্রিপশন স্থগিত করেন, তখন সাবস্ক্রিপশনের সমস্ত আইটেম একই সময়কালের জন্য স্থগিত হয়ে যায়।

আপনি যখন কোনো সাবস্ক্রিপশন স্থগিত করেন, তখন SUBSCRIPTION_DEFERRED টাইপের একটি SubscriptionNotification মেসেজ পাঠানো হয়। স্থগিতের সময়কালে, ব্যবহারকারী আপনার কন্টেন্টে সম্পূর্ণ অ্যাক্সেস সহ সাবস্ক্রাইব করা থাকেন, কিন্তু তার থেকে কোনো চার্জ নেওয়া হয় না। সাবস্ক্রিপশন নবায়নের তারিখটি নতুন তারিখ অনুযায়ী আপডেট করা হয়।

প্রিপেইড প্ল্যানগুলির ক্ষেত্রে, আপনি মেয়াদ শেষ হওয়ার সময় পিছিয়ে দিতে ডিফার বিলিং এপিআই (defer billing API) ব্যবহার করতে পারেন।

একটি ডেফার্ড সাবস্ক্রিপশনের জন্য সাবস্ক্রিপশন রিসোর্সটি নিম্নলিখিত উদাহরণের মতো দেখতে হয়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_future,
      ...
    }
  ],
}

স্থগিত সাবস্ক্রিপশন

ব্যবহারকারীদের সাবস্ক্রিপশন সাময়িকভাবে বন্ধ রাখার সুযোগ দিয়ে আপনি স্বেচ্ছায় সাবস্ক্রিপশন ছেড়ে দেওয়া কমাতে পারেন। আপনি যখন এই বিরতি (pause) ফিচারটি চালু করবেন, তখন ব্যবহারকারীরা সাবস্ক্রিপশনের পুনরাবৃত্তির সময়কালের উপর নির্ভর করে এক সপ্তাহ থেকে তিন মাসের মধ্যে যেকোনো সময়ের জন্য তাদের সাবস্ক্রিপশন স্থগিত করতে পারবেন। এর ফলে সাবস্ক্রিপশনটি সাময়িকভাবে স্থগিত হয়ে যায়।

সাবস্ক্রিপশন পুনরাবৃত্তি সাপ্তাহিক মাসিক তিন মাস ছয় মাস বার্ষিক
উপলব্ধ বিরতির দৈর্ঘ্য * ১ সপ্তাহ
২ সপ্তাহ
৩ সপ্তাহ
৪ সপ্তাহ
১ মাস
২ মাস
৩ মাস
১ মাস
২ মাস
৩ মাস
১ মাস
২ মাস
৩ মাস
প্রযোজ্য নয়
যেকোনো সময় পরিবর্তন হতে পারে।

একটি সাবস্ক্রিপশন পজ শুধুমাত্র বর্তমান বিলিং পিরিয়ড শেষ হওয়ার পরেই কার্যকর হয়। সাবস্ক্রিপশন পজ থাকা অবস্থায়, ব্যবহারকারী সাবস্ক্রিপশনটি অ্যাক্সেস করতে পারেন না এবং তাদের নবায়নের মূল্যও পরিশোধ করতে হয় না। পজের মেয়াদ শেষে, সাবস্ক্রিপশনটি পুনরায় চালু হয় এবং গুগল সাবস্ক্রিপশনটি নবায়ন করার চেষ্টা করে। যদি পুনরায় চালু করার প্রচেষ্টা সফল হয়, তাহলে সাবস্ক্রিপশনটি আবার সক্রিয় হয়ে যায়। যদি পেমেন্ট সংক্রান্ত সমস্যার কারণে পুনরায় চালু করার প্রচেষ্টা ব্যর্থ হয়, তাহলে ব্যবহারকারী অ্যাকাউন্ট হোল্ড অবস্থায় চলে যান, যা চিত্র ৫ এবং ৬-এ দেখানো হয়েছে:

চিত্র ৫। একজন ব্যবহারকারী তার সাবস্ক্রিপশনটি প্রথমে থামান এবং তারপর পুনরায় চালু করেন।
চিত্র ৬। একজন ব্যবহারকারী তার সাবস্ক্রিপশনটি সাময়িকভাবে বন্ধ করেন এবং এরপর অ্যাকাউন্টটি স্থগিত করেন।

ব্যবহারকারী বিরতির সময়কালে যেকোনো সময়ে ম্যানুয়ালি সাবস্ক্রিপশন পুনরায় চালু করতে পারেন, যেমনটি চিত্র ৬-এ দেখানো হয়েছে। যখন কোনো ব্যবহারকারী ম্যানুয়ালি পুনরায় চালু করেন, তখন বিলিং তারিখটি ম্যানুয়ালি পুনরায় চালু করার তারিখে পরিবর্তিত হয়।

যখন কোনো ব্যবহারকারীর সাবস্ক্রিপশন পজ করা হয়, তখন প্লে বিলিং লাইব্রেরি queryPurchasesAsync() মেথডের মাধ্যমে সাবস্ক্রিপশনটি ফেরত দেয় না, যদি না QueryPurchasesParamsincludeSuspendedSubscriptions প্যারামিটারটি true সেট করা থাকে। যদি সাবস্ক্রিপশনটি রিজুম করা হয়, তাহলে queryPurchasesAsync() মেথডটি সেটি আবার ফেরত দেয়।

কোনো ব্যবহারকারী যখন তাদের সাবস্ক্রিপশন স্থগিত করেন, তখন তা জানতে RTDN-এর জন্য নজর রাখুন। এই নোটিফিকেশনগুলো আপনাকে আপনার অ্যাপের ব্যবহারকারীদের জানাতেও সাহায্য করে যে, তারা তাদের সাবস্ক্রিপশন স্থগিত করেছেন এবং সেটিতে তাদের অ্যাক্সেস নেই। এছাড়াও, ব্যবহারকারীকে যেকোনো সময় Google Play-এর একটি ডিপ লিঙ্ক ব্যবহার করে ম্যানুয়ালি তাদের সাবস্ক্রিপশন পুনরায় চালু করার একটি উপায়ও আপনার রাখা উচিত।

যখন আপনার ব্যবহারকারী তাদের সাবস্ক্রিপশনটি বিরতি (paus) দেওয়ার জন্য উদ্যোগ নেন, তখন SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED টাইপের একটি SubscriptionNotification মেসেজ পাঠানো হয়। এই সময়ে, ব্যবহারকারীর পরবর্তী নবায়নের তারিখ পর্যন্ত তাদের সাবস্ক্রিপশনে অ্যাক্সেস থাকা উচিত এবং সাবস্ক্রিপশন রিসোর্সটিতে autoRenewEnabled = true থাকে। এই পর্যায়ে subscriptionState ফিল্ডের মান SUBSCRIPTION_STATE_ACTIVE থাকে।

যখন পজ কার্যকর হয়, তখন SUBSCRIPTION_PAUSED টাইপের একটি SubscriptionNotification মেসেজ পাঠানো হয়। যখন এটি ঘটে, তখন ব্যবহারকারী তার সাবস্ক্রিপশনের অ্যাক্সেস হারান, এবং সাবস্ক্রিপশন রিসোর্সে autoRenewEnabled = true থাকে ও subscriptionState ফিল্ডটি SUBSCRIPTION_STATE_PAUSED এ সেট করা হয়। PausedStateContext অবজেক্টটি চেক করে আপনি দেখতে পারেন কখন সাবস্ক্রিপশনটি আবার রিনিউ হবে বলে আশা করা হচ্ছে।

বিরতির সময়সীমা শেষে সাবস্ক্রিপশনটি স্বয়ংক্রিয়ভাবে পুনরায় চালু হলে অথবা ব্যবহারকারী নিজে থেকে সাবস্ক্রিপশনটি পুনরায় চালু করার সিদ্ধান্ত নিলে, SUBSCRIPTION_RECOVERED টাইপের একটি SubscriptionNotification মেসেজ পাঠানো হয়।

বিরতির পর সাবস্ক্রিপশন পুনরায় চালু করার চেষ্টা করার সময় পেমেন্ট ব্যর্থ হলে SUBSCRIPTION_ON_HOLD টাইপের একটি SubscriptionNotification মেসেজ পাঠানো হয়।

উভয় পরিস্থিতিই অ্যাকাউন্ট হোল্ড- এ বর্ণিত পদ্ধতি অনুযায়ী পরিচালনা করা উচিত।

পুনরায় সাবস্ক্রাইব করুন

স্বয়ংক্রিয়ভাবে নবায়নযোগ্য সাবস্ক্রিপশন-ভিত্তিক প্ল্যানগুলোর ক্ষেত্রে, গুগল প্লে স্টোর একটি ‘পুনরায় সাবস্ক্রাইব করুন’ (Resubscribe) বাটন প্রদর্শন করতে পারে। এই বাটনটি ব্যবহারকারীদের সাবস্ক্রিপশনটি পুনরায় অ্যাক্সেস করার সুযোগ দেয়। বিভিন্ন কারণে এটি প্রদর্শিত নাও হতে পারে, যেমন—যখন কোনো সাবস্ক্রিপশনের মেয়াদ অনেক দিন আগে শেষ হয়ে গেছে।

চিত্র ৭। গুগল প্লে স্টোর অ্যাপের অ্যাকাউন্ট > সাবস্ক্রিপশন বিভাগে একটি বাতিল করা সাবস্ক্রিপশন এবং একটি পুনরায় সাবস্ক্রাইব করার বাটন দেখানো হচ্ছে।

যদিও বাটনটিতে সবসময় ‘পুনরায় সাবস্ক্রাইব করুন’ লেখা থাকে, এর কার্যকারিতা সাবস্ক্রিপশনের অবস্থার ওপর নির্ভর করে।

যখন কোনো সাবস্ক্রিপশন বাতিল করা হয় কিন্তু তার মেয়াদ শেষ হওয়ার আগে, ব্যবহারকারী তখনও সাবস্ক্রাইব করা থাকেন এবং সাবস্ক্রিপশনের সুবিধাগুলো পেতে থাকেন। যদি ব্যবহারকারী 'Resubscribe'-এ ট্যাপ করেন, তাহলে বাতিলকরণটি কার্যকরভাবে বাতিল হয়ে যায় এবং সাবস্ক্রিপশনটি আবার নবায়ন হতে থাকে। প্লে ডেভেলপার ডকুমেন্টেশন এবং এপিআই-তে এই কাজটি 'restore' নামে পরিচিত।

স্বয়ংক্রিয়ভাবে নবায়নযোগ্য সাবস্ক্রিপশনের মেয়াদ শেষ হয়ে গেলে, আপনি ব্যবহারকারীদের একই সাবস্ক্রিপশন বেস প্ল্যানটি পুনরায় কেনার অনুমতি দিতে পারেন। প্লে ডেভেলপার ডকুমেন্টেশন এবং এপিআই-তে এই কাজটি ‘রিসাবস্ক্রাইব’ নামে পরিচিত। আপনি প্লে কনসোলে অথবা এপিআই ব্যবহার করে প্রতিটি বেস প্ল্যানের জন্য এই অপশনটি কনফিগার করতে পারেন।

মেয়াদ শেষ হওয়ার আগে পুনরুদ্ধার করুন

যদি আপনার অ্যাপ কোনো ব্যবহারকারী একটি সাবস্ক্রিপশনের জন্য যোগ্য কিনা তা নির্ধারণ করতে শুধুমাত্র queryPurchasesAsync() পদ্ধতির উপর নির্ভর করে, তাহলে আপনার অ্যাপের উচিত সাবস্ক্রিপশন পুনরুদ্ধারের বিষয়টি স্বয়ংক্রিয়ভাবে পরিচালনা করা, কারণ queryPurchasesAsync() পদ্ধতিটি মেয়াদ শেষ হওয়ার আগেই বাতিল হওয়া কেনাকাটাগুলো ফেরত দিতে থাকে। একটি পুনরুদ্ধার করা সাবস্ক্রিপশন এমনভাবে নবায়ন হতে থাকে যেন সেটি বাতিল করা হয়নি।

যদি আপনার অ্যাপ কোনো ব্যাকএন্ডের সাথে সাবস্ক্রিপশন স্টেট সিঙ্ক্রোনাইজ করে, তাহলে আপনার SUBSCRIPTION_RESTARTED টাইপের একটি SubscriptionNotification মেসেজের জন্য লিসেন করা উচিত। এই RTDN পাওয়ার পর, আপনার অ্যাপ নোটিফিকেশনে সাড়া দিতে পারে, সাবস্ক্রিপশনটি এখন রিনিউ করার জন্য প্রস্তুত তা রেকর্ড করতে পারে এবং আপনার অ্যাপে রিস্টোরেশন মেসেজ দেখানো বন্ধ করে দিতে পারে। সাবস্ক্রিপশন রিসোর্সটি নিচের উদাহরণের মতো দেখতে হয়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date
      ...
    }
  ],
}

মেয়াদ শেষ হওয়ার পর পুনরায় সাবস্ক্রাইব করুন

যদি গুগল প্লে কনসোল বা এপিআই ব্যবহার করে কোনো স্বয়ংক্রিয়ভাবে নবায়নযোগ্য বেস প্ল্যানে ‘রিসাবস্ক্রাইব’ করার অনুমতি দেওয়া থাকে, তাহলে ব্যবহারকারীরা গুগল প্লে স্টোর থেকে মেয়াদোত্তীর্ণ সাবস্ক্রিপশনটি পুনরায় কিনতে পারবেন।

এগুলো নতুন কেনাকাটা। গুগল প্লে একটি একেবারে নতুন পারচেজ টোকেন ইস্যু করে, এবং আপনার ব্যাকএন্ড SUBSCRIPTION_PURCHASED টাইপের একটি RTDN গ্রহণ করে। এক্ষেত্রে, এই ধরনের আউট-অফ-অ্যাপ পারচেজের পারচেজ স্ট্যাটাসে মূল কেনাকাটার সাথে যুক্ত কোনো linkedPurchaseToken অন্তর্ভুক্ত থাকে না, কারণ মূল সাবস্ক্রিপশনটির মেয়াদ সম্পূর্ণরূপে শেষ হয়ে গেছে।

পুনরায় কেনা সাবস্ক্রিপশনগুলির জন্য সঠিক ব্যবহারকারী সংযোগ নিশ্চিত করতে এবং স্বীকৃতিবিহীন কেনাকাটার জন্য স্বয়ংক্রিয় অর্থ ফেরত রোধ করতে, আপনাকে অবশ্যই আপনার ব্যাকএন্ড সার্ভারে পুনরায় কেনাটি স্বীকার করতে হবে:

  1. RTDN থেকে প্রাপ্ত নতুন পারচেজ টোকেন ব্যবহার করে purchases.subscriptionsv2.get কল করুন। এই ধরনের আউট-অফ-অ্যাপ পারচেজের রেসপন্সে outOfAppPurchaseContext ফিল্ডটি অন্তর্ভুক্ত থাকে, যা শুধুমাত্র স্বীকৃতিহীন রিসাবস্ক্রিপশন পারচেজের জন্য উপস্থিত থাকে। এই ফিল্ডটি প্রদান করে:

    • expiredExternalAccountIdentifiers : একটি ExternalAccountIdentifiers অবজেক্ট, যাতে পূর্ববর্তী মেয়াদোত্তীর্ণ সাবস্ক্রিপশনের জন্য কনফিগার করা obfuscatedAccountId এবং obfuscatedProfileId ফিল্ডগুলো থাকে, যদি সেগুলো সেট করা হয়ে থাকে।
    • expiredPurchaseToken : সর্বশেষ মেয়াদোত্তীর্ণ সাবস্ক্রিপশনের ক্রয় টোকেন।

    আপনার ব্যাকএন্ডে নতুন ক্রয়টি খুঁজে বের করতে এবং সঠিক ব্যবহারকারী অ্যাকাউন্টের সাথে লিঙ্ক করতে এই শনাক্তকারীগুলির যেকোনো একটি ব্যবহার করুন।

  2. ক্রয়টি স্বীকার করতে purchases.subscriptions.acknowledge কল করুন।

    • ঐচ্ছিকভাবে, আপনি ব্যবহারকারীর obfuscatedAccountId এবং obfuscatedProfileId পাঠাতে পারেন, যদি আপনি ইন-অ্যাপ বিলিং ফ্লো চলাকালীন setObfuscatedAccountId এবং setObfuscatedProfileId ব্যবহার করে সেগুলো কনফিগার করে থাকেন।

এই সার্ভার-সাইড পদ্ধতিটি আপনাকে ক্রয়ের তারিখ থেকে তিন দিনের মধ্যে ক্রয়টি নিশ্চিত করার সুযোগ দেয়, এমনকি যদি ব্যবহারকারী আপনার অ্যাপটি না-ও খোলেন।

আপগ্রেড, ডাউনগ্রেড এবং পুনরায় সাবস্ক্রাইব

যখন কোনো ব্যবহারকারী সাবস্ক্রিপশনের মেয়াদ শেষ হওয়ার আগে আপনার অ্যাপ থেকে সাবস্ক্রিপশন আপগ্রেড বা ডাউনগ্রেড করেন, অথবা বাতিল করার পর নতুন করে সাইন আপ করেন , তখন পুরোনো সাবস্ক্রিপশনটি বাতিল হয়ে যায় এবং একটি নতুন পারচেজ টোকেনসহ একটি নতুন সাবস্ক্রিপশন তৈরি হয়।

এছাড়াও, গুগল প্লে ডেভেলপার এপিআই থেকে প্রাপ্ত সাবস্ক্রিপশন রিসোর্সে একটি linkedPurchaseToken ফিল্ড থাকে, যা সেই পুরোনো ক্রয়টিকে নির্দেশ করে যেখান থেকে ব্যবহারকারী আপগ্রেড, ডাউনগ্রেড বা পুনরায় সাবস্ক্রাইব করেছেন। আপনি সেই ফিল্ডের পারচেজ টোকেনটি ব্যবহার করে পুরোনো সাবস্ক্রিপশনটি খুঁজে বের করতে এবং বিদ্যমান ব্যবহারকারী অ্যাকাউন্টটি শনাক্ত করতে পারেন, যাতে আপনি নতুন ক্রয়টিকে একই অ্যাকাউন্টের সাথে যুক্ত করতে পারেন।

আপনার অ্যাপে কোনো ব্যবহারকারীকে আপগ্রেড, ডাউনগ্রেড বা পুনরায় সাবস্ক্রাইব করার বিকল্প দেওয়ার আগে, আপনাকে অবশ্যই বিদ্যমান সাবস্ক্রিপশনটি স্বীকার করতে হবে। বিদ্যমান সাবস্ক্রিপশনটি স্বীকৃতির অপেক্ষায় থাকলে, যেকোনো প্ল্যান পরিবর্তন বা পুনরায় সাবস্ক্রাইব করা ব্লক হয়ে যাবে।

যদি ব্যবহারকারী সফলভাবে আপগ্রেড, ডাউনগ্রেড বা পুনরায় সাবস্ক্রাইব করেন, তবে এটি একটি নতুন ক্রয় যা আপনাকে অবশ্যই স্বীকার করতে হবে। এটি করার জন্য প্রস্তাবিত উপায় হলো গুগল প্লে ডেভেলপার এপিআই (Google Play Developer API) ব্যবহার করা। সাবস্ক্রিপশন রিসোর্সটি নিম্নলিখিত উদাহরণের মতো দেখতে হয়:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "linkedPurchaseToken": old_purchase_token,
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      }
    }
  ],
}

মূল্য পরিবর্তন

স্বয়ংক্রিয়ভাবে নবায়নযোগ্য সাবস্ক্রিপশনের মূল্য পরিবর্তন করা এবং প্রয়োজন অনুযায়ী ব্যবহারকারীদের অবহিত করার বিষয়ে জানতে মূল্য পরিবর্তন সংক্রান্ত সর্বোত্তম অনুশীলন নির্দেশিকাটি দেখুন।

যখন কোনো মূল্য পরিবর্তন যোগ করা হয় এবং মূল্য পরিবর্তনের স্থিতির যেকোনো আপডেটের জন্য, আপনি SUBSCRIPTION_PRICE_CHANGE_UPDATED RTDN পাবেন। আপনি purchases.subscriptionsv2.get এন্ডপয়েন্টটি কোয়েরি করে একটি সাবস্ক্রিপশন রিসোর্স পেতে পারেন, যেটিতে সাবস্ক্রিপশনের প্রতিটি আইটেমের মূল্য পরিবর্তনের বিবরণ থাকবে।

যখন বিদ্যমান গ্রাহকদের জন্য ঐচ্ছিকভাবে মূল্য পরিবর্তন প্রয়োগ করা হয়, তখন ব্যবহারকারী নতুন মূল্যটি নিশ্চিত বা প্রত্যাখ্যান করার জন্য কোনো পদক্ষেপ নিলে আপনি একটি RTDN পাবেন।

ঐচ্ছিক মূল্য পরিবর্তনের জন্য ব্যবহারকারীর নিশ্চিতকরণ পরিচালনা করুন

যখন কোনো ব্যবহারকারী আপনার সাবস্ক্রিপশনের মূল্যবৃদ্ধি গ্রহণ করেন, তখন আপনি SUBSCRIPTION_PRICE_CHANGE_UPDATED টাইপের একটি SubscriptionNotification মেসেজ পান।

মূল্য পরিবর্তন প্রয়োগ করার পর নবায়নের বিষয়টি পরিচালনা করুন।

মূল্য হ্রাস পেলে, অথবা সাবস্ক্রিপশনের মূল্যবৃদ্ধি নবায়ন হলে, আপনি SUBSCRIPTION_RENEWED টাইপের একটি SubscriptionNotification বার্তা পাবেন। এই বিজ্ঞপ্তিটিকে অন্য যেকোনো নবায়নের মতোই বিবেচনা করুন।

যেসব ক্ষেত্রে ঐচ্ছিক মূল্যবৃদ্ধি গৃহীত হয় না, সেসব ক্ষেত্রে ব্যবস্থা নিন।

যদি কোনো ব্যবহারকারী বর্ধিত মূল্যে নবায়ন করার আগে আপনার প্রস্তাবিত মূল্যবৃদ্ধি গ্রহণ না করেন, তাহলে তিনি স্বয়ংক্রিয়ভাবে আনসাবস্ক্রাইব হয়ে যাবেন এবং আপনি SUBSCRIPTION_CANCELED টাইপের একটি SubscriptionNotification মেসেজ পাবেন। Cancellations অংশে বর্ণিত পদ্ধতি অনুযায়ী এই ইভেন্টটি পরিচালনা করুন।

ব্যবহারকারীরা একই পদ্ধতি অনুসরণ করে মূল্যবৃদ্ধি এড়ানোর জন্য তাদের সাবস্ক্রিপশন বাতিল করতে পারেন।

দক্ষিণ কোরিয়ার (KR) নতুন নিয়মাবলীর কারণে, KR অঞ্চলের সাবস্ক্রিপশন ব্যবহারকারীদের তাদের ফ্রি ট্রায়াল বা পরিচিতি পর্ব শেষ হওয়ার পরে যে কোনও মূল্যবৃদ্ধিতে সম্মতি দিতে হবে।

আপনাকে নিয়মটি মেনে চলতে সাহায্য করার জন্য, প্লে কোরিয়া অঞ্চলের ব্যবহারকারীদের সম্মতির প্রয়োজনীয়তা সম্পর্কে অবহিত করবে এবং ব্যবহারকারীদের কাছ থেকে প্রাপ্ত সম্মতির প্রতিক্রিয়াও সংরক্ষণ করবে। বর্ধিত মূল্য কার্যকর হওয়ার আগে যে সকল ব্যবহারকারী সম্মতি প্রদান করবেন না, তাদের সাবস্ক্রিপশন স্বয়ংক্রিয়ভাবে বাতিল হয়ে যাবে। প্লে থেকে পাঠানো বিজ্ঞপ্তি ছাড়াও, আপনি আপনার ব্যবহারকারীদের কাছে নিজস্ব মূল্যবৃদ্ধির বিজ্ঞপ্তিও পাঠাতে পারেন এবং আপনার বিজ্ঞপ্তিতে নির্দিষ্ট ম্যানেজমেন্ট পেজের লিঙ্কও প্রদান করতে পারেন।

When the consent period has begun or the user has provided consent, you will receive a SubscriptionNotification message with type SUBSCRIPTION_PRICE_STEP_UP_CONSENT_UPDATED .

Difference between price step-up and price change

A price step-up refers to an increase in the subscription price, due to a transition from one offer phase to another. For example, a subscription moving from a free trial to a regular price. You can use the offerPhase field in the subscription resource to identify the current phase of the subscription.

However, a price change refers to price updates initiated by you (developer) for the base plan price for a subscription. For example, opt-in price increase or opt-out price increase.

Handle lifecycle for prepaid plans

As with auto-renewing subscriptions, you must acknowledge prepaid plans after each new purchase . In the case of prepaid plans, you must fully process both the initial purchase and any top-ups, because the user has to go through the purchase flow every time.

Due to the potential for short prepaid plan durations, it's important to acknowledge the purchase as soon as possible. Prepaid plans with a duration of one week or longer must be acknowledged within 3 days. Prepaid plans with a duration shorter than one week must be acknowledged within half of the plan duration. For example, developers have 1.5 days to acknowledge purchase of a three-day prepaid plan.

Figure 8. Lifecycle states and transition events for subscription purchases.

A SubscriptionNotification message with type SUBSCRIPTION_PURCHASED is sent to your RTDN client whenever a prepaid plan subscription is purchased, including every top-up. Call the purchases.subscriptionsv2.get method to check for the latest prepaid plan subscription state.

A new purchase token is issued for top-up purchases, and you receive the previous purchase token in the linkedPurchaseToken field as part of the new subscription purchase state. The purchase token is valid from subscription signup until 60 days after expiration. After this date, the purchase token is no longer valid to use to call the Google Play Developer API.

The subscription resource for a prepaid plan purchase looks similar to the following example:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  "startTime": "2022-04-22T18:39:58.270Z",
  "regionCode": "US",
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "latestOrderId": "GPA.3333-4137-0319-36762",
  "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
  "lineItems": [
    {
      "productId": "prepaid_plan01",
      "expiryTime": expiry_date,
      "prepaidPlan": {
        "allowExtendAfterTime": timestamp_after_which_topups_are_allowed
      }
    }
  ]
}

You can see when the entitlement ends in the expiryTime field. Top-up purchases increase the entitlement time by accumulating it. That means that if the user tops up before their original entitlement ends, the new time is added on top of their previous expiration date.

You might want to display a message in your app informing the user that their prepaid subscriptions can be extended with a top-up. To know when a user will be able to top-up, check the allowExtendAfterTime field in the subscription resource.

Prepaid plans don't auto-renew, so they can't be canceled. If a user wants to cancel a prepaid plan, they can let it reach its expiration date.

SubscriptionPurchaseV2 fields for prepaid plans

New fields have been added to support prepaid plans, which are extended by the user instead of automatically renewing. All fields apply to prepaid plans as they do for auto-renewing subscriptions, with the following exceptions:

  • [New field] lineItems[0].prepaid_plan.allowExtendAfterTime : denotes when a user will be allowed to buy another top-up to extend their prepaid plan, as a user is allowed to have only one unconsumed top-up at a time.
  • [New field] SubscriptionState : specifies the subscription object state. For prepaid plans, this value is always either ACTIVE , PENDING , or CANCELED .
  • lineItems[0].expiryTime : This field is always present for prepaid plans.
  • paused_state_context : This field is never present, as prepaid plans cannot pause.
  • lineItems[0].auto_renewing_plan : Not present for prepaid plans.
  • canceled_state_context : Not present for prepaid plans, as this field applies only to users who actively cancel a subscription.
  • lineItems[0].productId : This field replaces subscriptionId from previous versions.