App Store Refund Management

Apple の CONSUMPTION_REQUEST の内側:返金の行方を決める半日

App Store の返金はすべて Apple の判断ですが、CONSUMPTION_REQUEST は購入に関する事実を伝えるための決まった期間を与えてくれます。しっかり回答すれば、不当な主張は却下されます。黙っていれば、Apple が耳にするのは顧客側の言い分だけになります。

5 min read
Apple の CONSUMPTION_REQUEST の内側:返金の行方を決める半日

App Store の返金はすべて Apple の判断ですが、Apple としても何も分からないまま判断したいわけではありません。返金リクエストが発生するとプロセスは一時停止し、あなたのサーバーに問い合わせが送られ、購入に関する事実を回答するための決まった期間が設けられます。実質的な内容で回答すれば、不当な主張は却下されます。黙っていれば、Apple が耳にするのは顧客側の言い分だけになります。

重要なポイント

  • App Store での返金リクエストが発生すると、Apple はあなたのサーバーに CONSUMPTION_REQUEST 通知を送信し、判断を下す前に最大12時間、証拠の提出を待ちます。

  • 回答するということは、Send Consumption Information エンドポイントをコンパクトなペイロードとともに呼び出すことを意味します。同意の有無、配信状況、サンプルの有無、消費量、そして希望する結果です。

  • 何も送らないこと自体が、ひとつの回答になります。Apple は顧客の主張とアカウント履歴のみを使って処理を進めます。

  • 同意は絶対的な条件です。顧客が消費データの共有に同意していない場合は一切応答すべきではないと、Apple のドキュメントにも明記されています。

  • 自動更新型のサブスクリプションでは、消費割合は Apple が経過時間から算出するため、独自の数値を指定するとエラーになります。

  • 手作業のプロセスではこの時間枠に間に合いません。恩恵を受けるのは、回答が自動的に作成・提出される仕組みを持つ開発者だけです。

App Store のすべての返金は、同じように始まります。誰かが reportaproblem.apple.com にアクセスし、購入を選択し、理由を選びます。

ほとんど回答されない通知

App Store Server Notifications V2 を設定しているアプリは、返金がリクエストされるとすぐに CONSUMPTION_REQUEST 通知を受け取ります。そのペイロードには、トランザクション、プロダクト、そして2024年以降は顧客が選択した理由(UNINTENDED_PURCHASE、FULFILLMENT_ISSUE、UNSATISFIED_WITH_PURCHASE、LEGAL、OTHER のいずれか)が含まれます。

そこから12時間が始まり、その間に Send Consumption Information エンドポイントを呼び出して、あなた側の記録を残すことができます。このエンドポイントが求める内容は意図的に最小限に絞られており、フラグと数値だけで構成された5つのフィールドしかありません。

  • customerConsented は、顧客が自身の利用データの共有に同意したかどうかを Apple に伝えます。典型的な値は true です。

  • deliveryStatus は、購入が届いて正しく機能したかどうかを Apple に伝えます。典型的な値は DELIVERED です。

  • sampleContentProvided は、事前に無料サンプルやトライアルが提供されていたかどうかを Apple に伝えます。典型的な値は true です。

  • consumptionPercentage は、消費された割合を Apple に伝えます。単位はミリユニット(100000 が100パーセント)で表されます。典型的な値は 67500 です。

  • refundPreference は、あなたが望む結果(承認、却下、または希望なし)を Apple に伝えます。典型的な値は DECLINE です。

consumptionPercentage が適用される範囲は限られています。消耗型アイテム、一回限りの購入、そして自動更新しないサブスクリプションです。自動更新型のサブスクリプションでは、請求期間内の経過時間から Apple 側で算出されるため、こちらが指定したどのような値も拒否されます。

送信した情報を Apple はどう扱うか

消費情報は、返金がどう決着するかを左右する入力情報として、Apple に明確に使用されます。何も送らなければ、判断は純粋に顧客の主張とアカウント履歴だけに基づいて下されます。証拠を送れば、争いのある返金リクエストはかなりの頻度で却下されます。

回答の仕組みを自前で、最初から最後まで構築する

この一連の流れに秘密めいたところは何もありません。ただし、そのすべてが、朝の3時であっても人の手を借りずに機能する必要があります。

1. 通知を確実に受け取れるようにする

App Store Connect 内で、アプリの App Information ページを開き、App Store Server Notifications の下で Production Server URL を設定し、Version 2 を選択します。消費リクエストは V1 では送信されません。以降、返金を含むすべての通知が、署名付きの JWS ペイロードとして POST でその URL に届くようになります。

2. 正しい鍵を生成する

回答の認証には In-App Purchase key を使用します。これは Users and Access の Integrations セクションで作成します。これは独立した種類の鍵であり、隣に並んでいる App Store Connect API key ではこれらの呼び出しを認証できません。.p8 ファイルはちょうど一度だけダウンロードでき、その後はリクエストごとに短命な ES256 JWT を発行します。

3. 検証し、紐付け、判断する

届いた CONSUMPTION_REQUEST 通知は、内容のどの部分であれ信頼する前に、JWS 署名チェーンを Apple のルート証明書と照合して検証する必要があります。次に、購入時に付与した appAccountToken の UUID などを手がかりに、トランザクションをユーザーに紐付け、実際の利用状況を取得します。その上で方針を決めます。好意的に対応すべき状況は譲歩し、プロダクトが明らかに消費されている場合は異議を唱えます。

4. 時間切れになる前に提出する

その5つのフィールドを、該当するトランザクション ID に対して、12時間以内に Send Consumption Information エンドポイントへ PUT します。ほとんどの人がつまずくミスが2つあります。ひとつは割合がミリユニットで表されることで、100% は100万ではなく100000を意味します。もうひとつは同意がすべての前提になっていることです。Apple 自身のドキュメントが、顧客の同意がない場合は一切応答すべきでないと明記しているためです。この仕組みを実装する前に、同意に関する文言を利用規約に盛り込んでおきましょう。

多くの開発者が機会を逃す理由

半日という時間枠は、人が運用するものにとっては過酷です。通知は土曜日の午前3時にも届きます。求められるのは、Apple の JWS 署名チェーンを検証し、トランザクションをユーザーに紐付け、消費割合をミリユニットで算出し、JWT 認証された API を呼び出せるサーバーです。それもリクエストひとつひとつに対して、永続的にです。

実務上、チェックリストは次のようになります。

  • App Store Server Notifications V2 を設定すること。これがなければリクエストはそもそも届きません。

  • 署名付きペイロードを信頼する前に、Apple の証明書チェーンに照らして検証すること。

  • トランザクションを自社システム内のユーザーに紐付けること。通常は購入時に付与した appAccountToken を用います。

  • 消費割合は推測ではなく、実際に記録された利用状況から算出すること。

  • 時間枠が開いている間に、In-App Purchase key を使って Send Consumption Information を呼び出すこと。

Refund Sensor は、この負担を代わりに担うために存在します。誰も叩き起こすことなく、時間枠に十分な余裕を持って、証拠のそろった完全な回答を提出します。

これらのルールが記載されている場所

よくある質問

それでも返金の判断は下されますが、今度は顧客の主張とアカウント履歴のみに基づくことになります。購入が正しく届き、十分に使用されたことを示せる唯一の機会を失うことになります。実際のところ、未回答のリクエストはかなり高い割合で承認されています。

必要です。customerConsented は true でなければならず、そのフラグの背後にある同意も本物でなければなりません。通常はデータ共有を扱う法的文書のいずれかで取得します。Apple 自身のガイダンスでも、そうした同意が存在しない場合は通知にまったく応答しないようにと開発者に伝えています。

自動更新しない種類のサブスクリプションに限られます。自動更新型のサブスクリプションでは、消費量は現在の請求期間内の経過時間から Apple 側で算出されるため、こちらから指定した割合は API に拒否されます。それでも返金に関する希望(refundPreference)は引き続き考慮されます。

In-App Purchase key を使用します。これは App Store Connect の「Users and Access」内の「Integrations」セクションで生成します。App Store Connect API key とは別物で、.p8 ファイルは作成時に一度だけダウンロードできます。

本番環境では通知から12時間が認められています。Sandbox 環境ではわずか5分しかなく、これは Apple が人手ではなく自動化を前提としていることを、かなり明確に物語っています。

#consumption request#send consumption information#app store server notifications#refunds#storekit#ios
Refund SensorRefund Sensor TeamRefund defense for App Store and Google Play developers