Payment
Overview
アプリ内課金についてまとめるセクション。
アプリ内課金の仕組み
アプリ内課金ではレシートという用語が出てくる。
これはアプリ内課金を行なったときに App/Play Store が発行してくれるデータで、購入した内容や日時、サブスクリプションの場合は期限が切れる日時などが入っており、アプリ側で取得できる。
通常は、base64エンコードした文字列にしてサーバーとやり取りする。
このレシートが改ざんされていないかどうかは Apple/Google に問い合わせるしかなく、問い合わせにはSecretKey的なものを使用するのでセキュリティの観点から通常はバックエンドで行う。
上記を踏まえた上で、アプリ内課金を実装する場合の一般的な処理の流れは以下のようになる。
- アプリ側で決済処理を行う
- アプリ側で取得できるレシートをバックエンドに送る
- バックエンドで受け取ったレシートをApple/Googleに問い合わせてレシートを検証する
- レシートが正しい場合はレシート情報を元に、サブスク加入状態にする
課金アプリの歴史
課金モデルがマネタイズの中心となる前は、「無料アプリ + 広告」モデルが中心。
「無料アプリ + 広告」モデルはアクセス数がベースになるため収益には莫大なトラフィックが必要となる。
無料アプリ + 広告モデルについて
無料アプリ + 広告は別名でフリーミアムと呼ばれるモデル。
有料でアプリを買うという行為は敷居が高かったため、フリーミアムが台頭していた。
無料アプリ + 広告モデルの仕組み
「無料アプリ + 広告」で多い方式。
- インプレッション方式(CPM)
- 成果地点は利用者が広告を表示したタイミング
- クリック方式(CPC)
- 成果地点は利用者が広告をクリックしたタイミング
成果地点とはADネットワークがアプリ(メディア)に対して報酬を支払うタイミング
アプリならではの方式として、インストール方式(CPI)というのも一時盛り上がった。
利用者が広告を表示しクリック、そしてインストールするタイミングが成果地点。
また起動方式(CPA)という方式もあり、インストールするタイミングが成果地点。
リワード方式とも呼ばれ、利用者が広告アプリをインストールすることで利用者がアプリ内で利用できる報酬を得る方式も存在する。
ただしこの方式は不正にランキングを操作できることからAppleからはアプリのリジェクト対象になった。
アプリ内課金の手数料
アプリの販売では、AppStoreとGoogle Playのいずれの場合でも取引手数料としてアイテム価格の30%が差し引かれる。
また1つの販売アイテムに設定できる金額は各マーケットによって定義されている。
- App Store
- 120円から118,800円まで
- Google Play
- 99円から48,000円まで
フリーミアムモデル
フリーミアムというのは入り口としてのサービル利用は無料でその後の追加機能に関して料金を支払うモデル。
開発者に求められる「マネタイズ力」
現在は無料アプリで広告バナーを貼っていれば収益が得られるという時代ではない。
さらに利用者は「一発ネタ」に飽きている。
広告以外では必ずしも大量の利用者を必要としないアプリ課金は需要がある。
開発者がアプリ内課金でマネタイズを実現するために必要なことを考えた時に、地道で継続的な作り込みが必要になってくる。
競合調査やリリース後のユーザー行動分析などを通じて課金モチベーションを研究する。
ユーザー体験としてグラフィックや使い心地などを研究する
設計段階から明確にするべきこと
どんな利用者にどんなアイテムを買ってもらうのかイメージすること。
具体的にはDAU(Daily Active Users)、課金率、課金単価、月間課金額などのいわゆるKPI(Key Performance Indicators)を明確にするべき。 そうすることで必然的にプロモーション戦略やアイテムのタイプなどが決まってくる。
1人から得られる種益
広告においては1人あたりの利用者から得られる収益は限られる。
1利用者の成果数はADネットワークで技術的に制限されている。
クリック型の広告の場合、1利用者が1日で同じ広告を何度クリックしても成果としては1としてクリックされる。
ASO
WebでいうSEOと同じようなもの。
- インストール数
- アクティブユーザー数
- 起動時間
アプリ内課金の3代モデル
アプリ内課金で取り扱われるアイテムを「プロダクト」と呼ぶが、次の4種類に分類される。
1. 消費型/消耗型
「消費型」は何度も購入できるアイテム。
現在はバーチャル通貨が一般的。利点としてはバーチャル通貨を介して取得するアイテムのバリエーションが柔軟になる。
- iOSの場合は「消耗型」を選択する。
- Androidの倍は設定の都合上「消費型」と「非消費型」に分けられない。
「管理対象のアイテム」を選択し、プログラム側で制御する必要がある。
使用用途としては、キャンペーンなどで無料でバーチャル通貨を利用者に配布すること。
マーケティングとしては良い。
ゲームアプリで利用する体力回復アイテムやサービス内で利用する仮想通貨など。
現在はサードパーティ制のSDKなどアプリのアップデートを必要とせずにダッシュボードからアイテムを追加できるシステムなども存在する。
開発工数の削減や運用負荷の軽減目的で検討に加えても良い。
2. 非消費型/非消耗型
「非消耗型」は買い切り型ともいえ、一度購入したら無制限に利用できる。
- iPhoneの場合は「非消耗型」を選択する
- Androidの場合は「管理対象のアイテム」を選択する
ゲームアプリにおける新ステージや有料機能の開放など
3. 定期購入型/定期購読型
所定の時間を経過したら自動で定期購読されるタイプ。
月額制のプレミアム会員、月刊誌の購読など
4. 非定期購入型
購入後、所定の時間が経過したら再度購入できるタイプ。
このタイプはAndroidには存在しない
アーカイブオンラインカタログの年間登録など
利用者の購入方法
利用者はAppleやGoogleアカウントに登録してあるアカウント情報や決済情報を利用して決済する。
返金対応
各ストアで対応方法が異なる
- Apple
- 顧客がApple supportに依頼
- 非定期購読の場合は、Platform Server Notificationsの設定が必要
- Google Play
- RevenueCat管理画面から返金可能
- Google側で返金された場合は、最大24時間のラグがでる
猶予期間(Grace Period)
概要
Grace Period とは、サブスクリプションの自動更新において 請求に問題が発生した場合でも一定期間は「解約扱いにせず」アクセスを維持できる 仕組み、またはその期間のこと。
この期間中にユーザーが支払い方法を修正すれば、更新サイクルを保ったまま継続できます(後述の「再請求(Billing Retry)」とは別の概念)。
Grace Period = アクセス維持のための猶予
Billing Retry = 請求の再試行を続ける期間(アクセス維持の可否とは別)
両者は混同しがちなので注意
ストア別の挙動まとめ
| 項目 | App Store (Apple) | Google Play (Android) |
|---|---|---|
| 有効化/設定 | App Store Connect のアプリ単位で有効化。個々のプロダクトごとの設定不可。 | Play Console の**サブスクリプション(ベースプラン)**ごとに長さを設定/無効化可能。 |
| 期間の選択 | 3日 / 16日 / 28日。週次プランは最大 6 日、月/年プランは最大 28 日。 | Console で調整可。0日にしても 24 時間の「サイレント猶予」(最低 1 日)は発生。 |
| 猶予期間中のアクセス | 維持される(有効化している場合)。 | 維持される。 |
| 猶予期間終了後 | 「Billing Retry」状態は最大 60 日間継続(Apple が毎日再試行)。アクセスは停止。 | 「アカウントの一時停止(Account hold)」へ遷移。アクセスは停止。 |
| 再請求(リトライ) | 最大 60 日間、毎日再試行。 | 期間内に定期的に再試行。 |
| 通知/イベント | App Store Server Notifications v2: DID_FAIL_TO_RENEW(subtype:GRACE_PERIOD), GRACE_PERIOD_EXPIRED, DID_RENEW(subtype:BILLING_RECOVERY)など。 | RTDN: SUBSCRIPTION_IN_GRACE_PERIOD, SUBSCRIPTION_ON_HOLD, SUBSCRIPTION_RECOVERED, SUBSCRIPTION_RENEWED, SUBSCRIPTION_EXPIRED など。 |
参考: Apple — Billing Grace Period 設定 / Handling Subscriptions Billing / App Store Server Notifications
Google — Subscription lifecycle / Real‑time developer notifications
App Store(iOS)の詳細
-
有効化と期間
App Store Connect の「サブスクリプション」→「請求の猶予期間」で 3/16/28 日から選択。週次プランは最大 6 日、月/年は最大 28 日が適用範囲。アプリ単位で全プロダクトに一括適用。 -
アクセスと売上の取り扱い
Grace Period を有効にすると、支払い失敗中も期間内は有料コンテンツへのアクセスを維持。この間に回収できれば利用日数や収益の不利益は発生しない(更新日は維持)。 -
Billing Retry(請求再試行)
更新失敗時、最大 60 日間は App Store が毎日請求を再試行。- フラグ: レシート検証で
is_in_billing_retry_periodを確認。 - Grace Period を有効にしていない場合、Billing Retry 中でもアクセスは停止(=Grace はアクセス維持の設定)。
- フラグ: レシート検証で
-
通知/イベント(サーバ連携)
App Store Server Notifications v2 例:DID_FAIL_TO_RENEW(subtype: GRACE_PERIODの場合、猶予期間中)GRACE_PERIOD_EXPIRED(猶予期間終了)DID_RENEW(subtype: BILLING_RECOVERYの場合、請求回復による再開)EXPIRED(subtype: BILLING_RETRYは 60 日の再試行満了による失効)
-
実装ポイント(サーバ)
- 最新トランザクション/レシートを検証して現在の状態を判定(
is_in_billing_retry_period/grace_period_expires_date/expires_date等)。 - Grace 中はアクセス維持+アプリ内で「決済情報の更新」を促す UI を表示。
- Grace 終了後~Billing Retry 中はアクセス停止。ただし再請求成功時に自動復帰するため、通知処理で即時反映。
- 最新トランザクション/レシートを検証して現在の状態を判定(
Google Play(Android)の詳細
-
Grace Period と Account hold
支払い失敗時のリカバリーは Grace → Account hold の 2 段階(デフォルト)。- Grace 中はアクセス維持。
- Grace 終了後は Account hold に遷移し、アクセス停止。
- Console で Grace の長さを調整/無効化でき、0日にしても 24 時間のサイレント猶予(最低 1 日)は発生。
-
設定単位
Play Console の ベースプランごとに Grace/Account hold の長さを設定可能。 -
通知/イベント(サーバ連携)
RTDN(Real‑time developer notifications) を必ず受け取り、イベントごとに Google Play Developer API(Subscriptions v2) で実体を照会する。
代表的な通知:SUBSCRIPTION_IN_GRACE_PERIOD(猶予期間に突入)SUBSCRIPTION_ON_HOLD(アカウント一時停止に突入)SUBSCRIPTION_RECOVERED/SUBSCRIPTION_RENEWED(復旧/更新)SUBSCRIPTION_EXPIRED(失効)
-
実装ポイント(サーバ/クライアント)
- バックエンドは RTDN 受信後、
purchases.subscriptionsv2.get()を呼び出し権利状態を確定。 - クライアントは In‑App Messaging / 深いリンクで支払い方法の修正画面へ誘導。
- Account hold 中は entitlement をブロックし、支払い復旧時に即時復帰。
- バックエンドは RTDN 受信後、
よくある誤解の整理
- 「Grace を OFF にしても 60 日間請求は試みられる」は 正しい(=Billing Retry の動作)。
ただし アクセスは維持されない。アクセス維持をしたい場合は Grace Period を ON にする。
実装チェックリスト
- App Store: Grace の日数(3/16/28)と対象(有料更新のみ or すべて)、**適用環境(本番/Sandbox)**を設定。
- Google Play: ベースプランごとに Grace と Account hold の長さを設定(0 日でもサイレント猶予は 24 時間)。
- 双方とも**サーバ通知(ASDN v2 / RTDN)**を受信し、バックエンドで最終状態を確定。
- Grace 中はアクセス維持、終了後は停止のポリシーを統一。UI で決済修正を促す導線を用意。
Billing Retry
概要
Billing Retry は請求に失敗した後にストア側が支払いの回復(回収)を自動的に試みる期間・挙動の総称。Grace Period(アクセス維持の設定)とは別概念で、Grace を OFF にしていても Billing Retry は行われる。
ストア別の要点
| 項目 | App Store (Apple) | Google Play (Android) |
|---|---|---|
| 位置づけ | 独立したリカバリ期間(Grace とは別)。 | 明示的な「Billing Retry」というラベルはない(Grace → Account hold の期間に再請求が行われる)。 |
| 期間 | 最大 60 日間、毎日再試行。 | Console 設定に依存。Grace 期間とAccount hold 期間のあいだでストアが定期的に再請求。 |
| アクセス | Grace を ON にしている間のみアクセス維持。Grace が切れる/無効の場合は停止。 | Grace 中は維持、Account hold 中は停止。 |
| サーバ通知 | App Store Server Notifications v2(例: DID_FAIL_TO_RENEW, GRACE_PERIOD_EXPIRED, DID_RENEW with BILLING_RECOVERY)。 | RTDN(例: SUBSCRIPTION_IN_GRACE_PERIOD, SUBSCRIPTION_ON_HOLD, SUBSCRIPTION_RECOVERED, SUBSCRIPTION_RENEWED, SUBSCRIPTION_EXPIRED)。 |
| 状態の確定 | レシート検証+ASDN v2のイベントで判定(is_in_billing_retry_period など)。 | RTDN を受け、Subscriptions v2(purchases.subscriptionsv2.get)のレスポンスで事実確定。 |
タイムライン例
App Store(Grace ON の例)
T+0 自動更新の請求失敗 → Billing Retry 開始(アクセスは維持)
T+X ストアが毎日再試行(最大 60 日)
成功 `DID_RENEW (subtype: BILLING_RECOVERY)` → 権利延長/アクセス継続
満了 `EXPIRED (subtype: BILLING_RETRY)` → 失効
Google Play
T+0 請求失敗 → Grace 期間(アクセス維持)
Grace 終了 Account hold(アクセス停止)
成功 `SUBSCRIPTION_RECOVERED` or `SUBSCRIPTION_RENEWED` → 復旧/延長
満了 `SUBSCRIPTION_EXPIRED` → 失効
実装ポイント(Backend)
- 通知駆動で即時同期:
- App Store: ASDN v2 をトリガに最新トランザクションを検証し、
DID_RENEW/BILLING_RECOVERYで延長確定。 - Google Play: RTDN 受信 →
purchases.subscriptionsv2.getを呼んで最新状態を反映。
- App Store: ASDN v2 をトリガに最新トランザクションを検証し、
- 延長は“更新確定”後:Billing Retry 中は権利を延長しない(UI上の文言のみで案内)。
- 冪等性:同一契約/期間への更新処理はアップサートで冪等に。
- 監査/ロギング:失敗→復旧のイベント系列を時系列で保持(サポート対応・会計監査向け)。
実装ポイント(クライアント/UI)
- 明確な案内:「支払い方法の更新が必要です」「請求を再試行しています」など、ストア別の導線(App Store/Play)へディープリンク。
- 状態連動:Grace 中は機能維持、Account hold/Retry 中は一部機能をロック(読み取り専用等)するなど段階的な制御。
Play Console の運用ヒント
- 週次プランは短め(例: Grace 3–7日)/ 月次は中程度(例: 7–14日)/ 年次は長め(例: 14–28日)を検討。
- Account hold は 30–60 日の範囲で検討(事業の許容損益や回収率の実績に合わせて調整)。
- KPI 例:
Retry成功率(期間別)、Grace中CVR、Hold復旧率を定常監視。
与信ホールド
与信ホールド(Account Hold)は、サブスクリプションの自動更新において支払いが失敗し、猶予期間(Grace Period)が終了した後に発生する状態です。
この状態では、ユーザーの支払い情報に問題があり、課金が保留されているため、サービスへのアクセスが一時的に停止される。
ユーザーが支払い情報を更新し、問題が解決されると、サブスクリプションは復旧し、アクセスが再開される。