Carpe Diem

備忘録

App Store の In-App Purchase の Grace Period対応

概要

AppStoreでGrace Period機能がリリースされたました。
これはその機能の検証を行った結果です。

Appleは気づいたら仕様変更することもちょこちょこあるので、こちらの結果が常に正しいとは信じず参考程度に捉えてください

前提知識

サブスクリプション決済手段を登録すると、毎月 or 毎年自動で更新されます。
しかしキャリア決済の上限に達したり、カードの上限・更新期限に達して意図せずお金を支払えないケースはサービス側が想像するよりもずっと多いのです。

なのでAppleに限らずGoogleもStripeも、決済問題が解決するまで一時的に解約させずに猶予期間というものを提供しています。

サービス側は猶予期間に入ってしまったユーザに「決済手段に何らかの問題が発生して支払いできてませんよー」と注意喚起を通知し、ユーザ側で問題を解決してもらえるように促す対応が必要です。

猶予期間の課金サイクル

以前の仕組み

以前のAppStoreはユーザの決済手段に問題が発生すると、最大60日のbilling retryが行われていました。
※ここで「最大」と書いているのは、60日以内にretryが終了してしまうケースもあるため。詳細はブラックボックス

f:id:quoll00:20191125125615p:plain

ref: https://developer.apple.com/documentation/storekit/in-app_purchase/reducing_involuntary_subscriber_churn?language=swift

期間内にユーザが決済問題を解決すると、その時点から改めて購読の起点日をセットし、購読を再開します。

GooglePlayでいうAccountHoldに近いです。

ユーザへの対応

購読の起点日が変わるということは、billing retryの期間中サービス側はお金をもらえないことになります。
なので一般にサービスサイドはユーザが購読できていない状態(=freeステータス)としてハンドリングすべきです。

ユーザには

決済に問題があって支払いができていないので、有料状態から無料状態へ変更しました。決済問題を解決してもらえれば自動で有料状態に戻ります。

といった通知を表示して問題解決を促します。

今回のGrace Period

今回のGrace Periodは、有効にすると

  • Grace Period内の復活ならbilling anchor(購読の起点日)は変わらない
  • Grace Period以降の復活ならbilling anchor(購読の起点日)は復活日に変わる

という挙動になります。後者は以前の仕組みと同様です。

f:id:quoll00:20191125125551p:plain

ref: https://developer.apple.com/documentation/storekit/in-app_purchase/reducing_involuntary_subscriber_churn?language=swift

ユーザへの対応

Grace Period期間内にユーザが決済問題を解決すれば、購読の起点日に変更はありません。つまりサービスサイドはお金をその期間もユーザからもらえるということです。
なのでサービスサイドはユーザを購読中としてハンドリングすべきです。

ユーザには

決済に問題があって支払いができていないです。今はまだ有料状態ですが、xx月oo日(Grace Periodの終了時刻)に無料状態へ変わります。それまでに決済問題を解決してください。

といった通知を表示して問題解決を促します。

レシートの変更点

レシート的にはpending_renewal_infograce_period_expires_xxxが増えます。

  "pending_renewal_info": [
    {
      "expiration_intent": "2",
      "auto_renew_product_id": "example.premium.plan",
      "is_in_billing_retry_period": "1",
      "auto_renew_status": "1",
      "price_consent_status": "",
      "product_id": "example.premium.plan",
      "original_transaction_id": "xxxxxxxxxxxxxxxxx",
      "grace_period_expires_date": "2019-10-18 08:33:54 Etc/GMT",
      "grace_period_expires_date_ms": "1571387634000",
      "grace_period_expires_date_pst": "2019-10-18 01:33:54 America/Los_Angeles"
    }
  ]

こちらの値を利用して猶予期間をハンドリングします。

Q & A

その他気になった点の検証結果です。

Q. 常にgrace_period_expiresフィールドは存在するのか。それともgrace period期間に入ったユーザのみか

grace period期間ユーザのみでした。

ただしgrace period期間を過ぎても決済問題が解決されなかった場合、grace_period_expires_xxxフィールドは残ったままだった。

Q. grace period中、通常のexpiresは延びるのか(google, stripeは延びる)

延びませんでした。

Q. expiration_intentは?

10件ほどサンプリングしたが全てexpiration_intent: 2でした。 つまり課金エラー。

f:id:quoll00:20191125130253p:plain

ref: レシート検証 プログラミングガイド

Q. auto_renew_statusは?

10件ほどサンプリングしたが全てauto_renew_status: 1でした。

Q. is_in_billing_retry_periodは?

10件ほどサンプリングしたが全てis_in_billing_retry_period: 1でした。

Q. 過去のbilling retry中レシートはどうなるか?

過去のレシートは変わりませんでした。

Q. 反映時間はどれくらいか?

5時間程度かかったり、15時間程度かかるサービスも。
最低でも1日程度かかると見積もった方が良さそう。

まとめ

ユーザの決済手段の問題における意図しない解約は想像よりも非常に多いです。
なのでサブスクリプション型の商品を提供するサービスはこういった猶予期間の活用が必須と言えるでしょう。

ソース