header image

枝折

AppStoreServerNotification V2 の notificationType まとめ

CREATED: 2024 / 01 / 29 Mon

UPDATED: 2024 / 01 / 29 Mon

V1 から V2 に切り替えたのでメモメモφ(.. )

AppStoreServerNotification の V1 を V2 に切り替えた

うちでリリースしているアプリではアプリ内ポイント(消耗型課金)とサブスクリプション(自動更新型課金)が利用できるようになっているので、AppStore のサーバー通知では消耗型課金の返金処理と自動更新型課金の更新、キャンセル、返金を対応できるようにしています。

V1 が deprecated になっているのもあるのですが、V2 の方が取得できるフィールドが豊富でサーバー側の処理が楽になりそうだったので、最近対応方法を調査していました。

その際にまとめた notificationType についてここにまとめておきます。 英語ですが公式ドキュメントは以下です。 notificationType

V2 では notificationType と subtype の組み合わせでそのイベントの詳細を把握することができます。

例えば、DID_CHANGE_RENEWAL_PREF notificationType には UPGRADE もしくは DOWNGRADE subtype が含まれます。 これにより「自動更新サブスクリプションのプランが変更され、アップグレードもしくはダウングレードされた」ことを確認することができます。

CONSUMPTION_REQUEST

CONSUMPTION_REQUEST は消耗型課金の返金対応のために、Apple から返金処理をスムーズに進めるための情報提供をリクエストされた時に送信されます。 この通知から12時間以内に AppStoreServerAPI を呼び出して Apple へ返金対象の課金アイテムの情報提供を行うと、返金処理が通常より早く実施されるようです。 Send Consumption Information

ですが、特に返金の速度を気にしないのであれば気にする必要はなさそうな印象ですね。

DID_CHANGE_RENEWAL_PREF

これはうちのアプリでも重要な通知タイプでした。 アップグレードとダウングレードのようなプラン変更が発生した場合に通知されます。

notificationType が DID_CHANGE_RENEWAL_PREF の場合、その subtype には UPGRADE か DOWNGRADE が入ります。 その名の通り、UPGRADE が入っている場合はそのイベントはアップグレードされたことを表し、 DOWNGRADE が入っている場合はそのイベントはダウングレードされたことを表します。

また、subtype がそもそも存在しないパターンも存在します。 これは、一度 DOWNGRADE したものの期限終了時までにそれを取り消した場合に通知されるようです。

iOS のアプリ内課金ではアップグレードは即時的に行われますが、ダウングレードはその周期の期限終了時までダウングレード前のティアは継続されます。 そのため、ダウングレードしても期限終了時までにそれを取り消すことができるわけです。

DID_CHANGE_RENEWAL_STATUS

DID_CHANGE_RENEWAL_STATUS はそのサブスクリプションの継続状態の変化を通知します。 これを用いてサブスクリプションが次の期限日時に更新されるか否かを判断することができます。

このイベントは subtype に AUTO_RENEW_ENABLED と AUTO_RENEW_DISABLED のいずれかを持ちます。 AUTO_RENEW_ENABLED は次の期限日時の更新が有効になったことを示しますので、無効になっていたものが有効になった時に通知されます。 AUTO_RENEW_DISABLED は次の期限日時の更新が無効になったことを示すので、ENABLED の逆です。

また、AUTO_RENEW_DISABLED はユーザーがサブスクリプションに対する返金をリクエストした際に AppStore が自動更新型サブスクリプションを無効にした際にも通知されます。

DID_FAIL_TO_RENEW

DID_FAIL_TO_RENEW は請求の問題でサブスクリプションの更新に失敗した際に通知されます。

その後サブスクリプションは60日間の請求リトライ期間に入り、その間に請求が成功した場合はその日からサブスクリプションが再開されます。 といっても請求が成功するまでサブスクリプションの機能をアプリ上で提供するか否かはサービス提供者の自由意志で決めることができます。 うちの場合はリトライ期間もサービス自体は提供し、リトライが完全に失敗してサブスクリプションがキャンセルされた時点でサービスの提供を止めています。

この通知の subtype は GRACE_PERIOD か何もないかのどちらかです。 GRACE_PERIOD が入っている場合は、そのサブスクリプションには猶予期間が設定されていることを示しています。 猶予期間は AppStoreConnect のアプリのサブスクリプションの項目から設定することができます。

猶予期間の設定

GRACE_PERIOD の間はサービスを提供するが、それを超過した場合はサービスを提供しないといった仕様にする場合はこちらを利用できそうですね。 請求リトライ期間(billing retry period)と猶予期間(grace period)については以下のドキュメントが参考になります。

Reducing Involuntary Subscriber Churn

猶予期間などの設定がない場合は subtype は存在しません。

DID_RENEW

DID_RENEW はサブスクリプションが正常に更新されたことを通知します。 subtype が BILLING_RECOVERY の場合は、前回更新に失敗した期限切れのサブスクリプションの更新が成功したことを示します。 subtype が存在しない場合は平穏無事に更新されたということです。

EXPIRED

EXPIRED もサービス連携を行う上で重要な通知タイプです。 そのままですが、サブスクリプションの期限が切れたことを通知します。

subtype には VOLUNTARY, BILLING_RETRY, PRICE_INCREASE, PRODUCT_NOT_FOR_SALE が入ります。 VOLUNTARY はその名の通り自主的な解約によりサブスクリプションの期限が切れたことを示します。 この通知を受けた際にはサービス側からユーザーへ提供している機能を無効化するなどの処理を行う必要があります。 BILLING_RETRY は請求リトライ期間である60日が超過したためにサブスクリプションの期限が切れたことを示します。

PRICE_INCREASE はサブスクリプションの価格が挙げられた際に、ユーザーの承認が得られずにサブスクリプションの期限が切れてしまった際に通知されます。 iOS アプリ内課金のアイテムの価格上昇時にはユーザーの承認が必要なため、このような状況で承認が得られなかった場合にこの通知が送信されるわけです。 ちなみに価格が安くなる分にはユーザーの承認は不要で、そのまま次の更新日に値段が切り替わるようになっています。 価格の管理

GRACE_PERIOD_EXPIRED

GRACE_PERIOD_EXPIRED はその名の通り、猶予期間が終了したことを通知します。 猶予期間は AppStoreConnect から設定可能ですので、そこで指定した期間が過ぎたことをこの通知によって把握できます。 請求リトライ期間にはサービスを提供しないようなアプリでは、この通知が届いた際にユーザーのメンバーシップ権限などを制限することができそうです。

OFFER_REDEEMED

OFFER_REDEEMED はうちのアプリではあまり関係がない通知でしたが、プロモーションオファーに関するものです。 アプリで設定しているオファーが利用された際に通知されます。

subtype が INITIAL_BUY の場合はユーザーが初回購入でオファーを利用したことを示し、RESUBSCRIBE の場合はユーザーが無効になったサブスクリプションを再登録したことを示します。 また、UPGRADE と DOWNGRADE も存在しますが、こちらもそれぞれのアクションを行った際にオファーが利用されたことを指します。 初回購入でも再登録でもアップグレードでもダウングレードでもない、通常の更新時にオファーを利用した場合は subtype が OFFER_REDEEMED となります。

PRICE_INCREASE

PRICE_INCREASE はアプリにおける自動更新型サブスクリプションの値上げが開始された際に通知されます。 値上げにはユーザーの同意が必要なのですが、この通知の subtype が PENDING の場合はそのユーザーがまだ同意に至っていないことを示します。 ユーザーが値上げ価格に同意した場合、subtype は ACCEPTED となって通知されます。 また、ユーザーの同意が必要ない場合、つまり値下げなどの場合には、自動的に ACCEPTED となるようです。

REFUND

REFUND はユーザーへの返金処理が完了したことを通知します。 通知ペイロードの revocationDate には返金された日時が含まれ、revocationReason にはその理由が含まれています。

REFUND_DECLINED

REFUND_DECLINED はアプリから以下のメソッドを利用して行われた返金リクエストが拒否された場合に通知されます。

beginRefundRequest(for:in:)
beginRefundRequest(in:)
beginRefundRequest(for:in:)
beginRefundRequest(in:)
refundRequestSheet(for:isPresented:onDismiss:)

うちの場合は返金リクエストは個別に行っていただくようにしているのでこちらはあまり関係がありませんでした。

REFUND_REVERSED

REFUND_REVERSED はユーザーからの異議申し立てのために、すでに承認されていた返金処理を AppStore 側がひっくり返した場合に通知されます。 すでに REFUND 通知を受け取ってサービスを無効にしていた場合などは、再度復元する必要があるかもしれません。 まあ、多分ほとんどないし、こういうことがあったとしても個別に復旧させるとかでも良い気がします。

RENEWAL_EXTENDED

RENEWAL_EXTENDED は特定のサブスクリプションの更新日時が延長されたことを通知します。 サービスがデータセンターの停電などの影響によって正常に稼働しないような時期があった場合などに、その補填として更新日時を延長することができます。

延長のリクエストは以下の AppStoreServer API を利用して行うことができるようです。 Extend a Subscription Renewal Date Extend Subscription Renewal Dates for All Active Subscribers

RENEWAL_EXTENSION

こちらの通知は AppStore がサブスクリプションの更新日時の延長処理対応を行なっていることを指すようです(おそらくアクティブなサブスクリプション登録者を順番に処理するようなイメージかと思われます)。 その結果は subtype に含まれ、これが SUMMARY の場合は全ての対象サブスクリプション登録者の延長処理が終了したことを示します。 FAILURE の場合は特定のサブスクリプションの延長処理が失敗したことを示します。

うちでは関係がなかったところなので試してはいませんが、FAILURE の場合は失敗したサブスクリプションの一覧でも取得できるのでしょうかね?

REVOKE

こちらもうちではあまり関係がなかったのですが、ファミリー共有で利用できていたアプリ内課金コンテンツが利用できなくなったことを指す通知のようです。 コンテンツの購入者がファミリー共有での購入を無効にしたり、ファミリーグループを抜けたり、返金を受け取った場合にこの通知が送信されるみたいですね。

SUBSCRIBED

SUBSCRIBED はユーザーがコンテンツをサブスクリプション購入した際に通知されます。 subtype が INITIAL_BUY の時は、ユーザーの初回購入であることを示します。 subtype が RESUBSCRIBE の場合は、ユーザーが同じサブスクリプショングループの同じもしくはそれ以外のサブスクリプションアイテムを再購入したことを示します。

こちらは自動更新型サブスクリプションを実装しているアプリでは重要な通知かと思われます。 初回登録を検知してユーザーへ初回ボーナスを付与したり、再登録時にお帰りプレゼントをしたりできそうです。

TEST

この通知は AppStoreServer API の以下のエンドポイントを呼び出した時に AppStore から通知されます。

Request a Test Notification

このエンドポイントを呼び出すことで、自分がホストしているサーバーに対して AppStore から正常に通知が届けられているかを確認することができます。

を仕舞い

最近 iOS の課金バックエンド周りをいじったのでこの話題について書いてみました。

こちらに英語ではありますが、状況ごとにどの通知を処理すべきかがまとめられているので参考になるかもです。 Handle use cases for subscription life-cycle events

仕舞いです。