Issue #891 / STG検証計画 / 2026-03-31

月額サブスク決済失敗時の
退会扱い問題 ― STG検証計画

STG環境での検証に入る前に、テストシナリオと期待する動作についてご確認ください。

検証手順
テストシナリオ一覧
背景・原因
処理の詳細

Stripe管理画面で「決済失敗」の通知設定を追加し、決済失敗時にサービス利用期限が正しく延長されるようになることをSTG環境で検証します。以下の手順で進めます。

決済失敗の起こし方

今回テストしたい「月額決済の失敗」は、サブスクリプションの月次更新タイミング(翌月の自動課金)で発生するものです。初回のサブスク申し込み(単発の決済)では発生しません。

そのため、Stripeが提供する「テストクロック」という仕組みを使います。テストクロックとは、テスト環境上で時間を早送りできる機能です。実際に1ヶ月待つことなく、「1ヶ月後に月次課金が走ったらどうなるか」をすぐに再現できます。

テストクロックを使った検証の流れ
1. テスト用サブスクを作成する

ササキのSTGアカウントで、正常なテストカードを使ってサブスクを申し込む

2. カードを「失敗するカード」に差し替える

Stripe管理画面で、支払い方法をテスト用の失敗カードに変更する

3. テストクロックで1ヶ月先に進める

Stripe上の時間を早送りして、翌月の自動課金タイミングを発生させる

4. 月次課金が失敗する

失敗カードのため課金が通らず、本番と同じ「決済失敗」が再現される

この方法により、本番で実際にユーザーが体験するのと同じ流れで決済失敗を再現できます。

1
準備 事前確認・データ記録
検証に必要なアカウントと現状データを確認する

ササキのSTGアカウントで、ミラーフィットアプリにログインできることを確認します。

そのアカウントが既にサブスク契約中かどうかを管理コンソールで確認し、テスト前のデータ状態(利用期限、支払いステータスなど)を記録しておきます。

Stripe管理画面(STG)で、現在の通知設定をスクリーンショットで保存しておきます。

Stripe管理画面でテストクロックを作成し、ササキのアカウントに対応するStripe顧客に紐づけます。

2
準備 テスト用サブスクの作成
正常なカードでサブスクを申し込み、月次課金が走る状態を作る

ササキのSTGアカウントで、正常なテストカード(4242 4242 4242 4242)を使ってサブスクを申し込みます。この時点ではまだ初回決済が成功し、サブスクが正常に開始されている状態になります。

続いて、Stripe管理画面でこのユーザーの支払い方法を「失敗するテストカード」(4000 0000 0000 0341)に差し替えます。このカードは登録自体は成功しますが、実際の課金時に失敗する特性を持っています。

3
テスト 修正前のバグ再現(Phase 1)
現状の設定のまま決済失敗を起こし、問題が再現されることを確認

Stripeの通知設定は変更せず、テストクロックで時間を1ヶ月先に進めて月次課金を発生させます。失敗カードに差し替え済みのため、課金が失敗します。

決済失敗 → 利用期限が延長されない
Stripe管理画面で「決済失敗」イベントは発生しているが、アプリに通知が届いていないことを確認する。管理コンソールでユーザーの利用期限が変わっていないことを確認する。
利用期限が変わらない=バグが再現できている
4
設定変更 Stripe通知設定の追加
STG環境のStripe管理画面で「決済失敗」の通知をアプリに送る設定を追加

Stripe管理画面の Developers > Webhooks から、STGのエンドポイントに invoice.payment_failed イベントを追加します。

アプリ側にはこの通知を受け取って利用期限を延長するコードが既にあるため、コードの変更は不要です。

5
テスト 修正後の正常動作を確認(Phase 2: 6シナリオ)
決済失敗・成功のさまざまなパターンが正しく処理されるか

通知設定を追加した状態で、テストクロックを使って再び月次課金の失敗を発生させ、今度は利用期限が正しく延長されることを確認します。さらに、リトライや成功復帰など複数のシナリオを検証します。

全7シナリオの詳細は「テストシナリオ一覧」タブの Phase 2 をご参照ください。

6
テスト 既存機能への影響確認(Phase 3: 3シナリオ)
今回の設定追加が、通常の購入・決済・返金などに悪影響を与えていないか

通知設定の追加が既存の決済フローに影響を与えていないことを確認します。

全7シナリオの詳細は「テストシナリオ一覧」タブの Phase 3 をご参照ください。

7
調査 データ形式不整合の調査(別検証)
利用期限の計算値にズレが生じる可能性がある既知の技術課題を調査

Stripeとアプリの間で使われているデータ形式のバージョンに不整合があり、利用期限を「請求期間の終了日 + 1ヶ月」で計算すべきところが、「現在日 + 1ヶ月」で計算される可能性があります。

致命的な差異ではありません(数日以内のズレ)が、正確な動作のためには対応が必要です。Step 5 の検証結果を踏まえて実際の影響を確認し、対応方針を決定します。

ユーザーへの影響

利用期限が数日ずれる可能性がありますが、サービスが即停止される現在の問題と比べると影響は軽微です。まず通知設定の追加(Step 3〜6)で致命的な問題を解消し、その後にこの精度の問題を対応します。

8
結果まとめ → 本番反映の判断
STG検証の結果を整理し、本番環境への反映可否を判断

Phase 1〜3 の全テストが完了し、問題がなければ本番環境のStripe管理画面に同じ通知設定を追加します。

データ形式不整合(Step 7)の対応が必要な場合は、本番反映のタイミングを調整します。

各フェーズのテストシナリオを一覧で示します。検証手順の Step 3・5・6 に対応します。

Phase 1 ― バグ再現(修正前)

ID タイトル 検証内容 想定される動き
1-1 決済失敗時の現状確認 通知設定が未追加の状態でテストクロックを使い月次課金を失敗させる。Stripe上でイベントは発生するがアプリに届かないことを確認 利用期限が延長されない(バグが再現される)

Phase 2 ― 修正後の正常動作確認

ID タイトル 検証内容 想定される動き
2-1 初回の決済失敗 有効なサブスクがあるユーザーで、テストクロックを進めて月次課金の失敗を発生させる 利用期限が約1ヶ月延長される。コンソールでもサブスクが有効のまま表示される
2-2 2回目以降のリトライ失敗 初回失敗の状態から、テストクロックをさらに進めて再度失敗させる リトライ回数が増加し、利用期限が再計算される。最初の失敗日時は保持される
2-3 重複通知の処理防止 Stripeから同じ決済失敗の通知が2回届いた場合に、データが二重更新されないか確認 2回目の通知は無視され、利用期限やリトライ回数に変化なし
2-4 リトライ期間中に決済成功 決済失敗が記録された状態で、カードを正常なものに差し替えてからテストクロックを進め、次のリトライで成功させる 失敗情報がすべてリセットされ、支払いステータスが「成功」に戻る
2-5 月次請求成功での期限延長 正常なカードで月次請求が成功した場合、利用期限が正しく延長されるか 利用期限が次の請求期間の終了日に更新される
2-6 複数種類の失敗通知の同時処理 Stripeが同一の決済失敗に対して複数種類の通知を送ることがある。利用期限が二重に更新されないか 利用期限の更新は1回だけ実行される

Phase 3 ― 既存機能への影響確認

ID タイトル 検証内容 想定される動き
3-1 新規サブスク購入 toCアプリからサブスクを新規購入し、正常に完了するか サブスクが作成され、コンソールに正しく反映される
3-2 通常の決済成功 失敗履歴がない通常状態での決済成功が問題なく処理されるか 支払いステータスが「成功」で正常処理
3-3 リトライ回数の上限 リトライ回数が上限(4回)を超えないことの確認 回数が正しく制御される

別検証 ― データ形式不整合

ID タイトル 検証内容 想定される動き
V-1 API バージョン不整合の影響確認 Phase 2 の検証時に、利用期限の計算値が「請求期間終了日 + 1ヶ月」か「現在日 + 1ヶ月」かを突き合わせて確認 数日のズレがある場合、データ形式不整合の影響が確認できる
V-2 対応適用後の検証 データ形式不整合の対応(設定変更 or コード修正)を適用した後に、利用期限が正確に計算されるか 利用期限が「請求期間終了日 + 1ヶ月」で正確に設定される

問題の概要

月額サブスクリプションの決済が失敗すると、ユーザーのサービス利用期限が延長されず、即座にサービスが使えなくなります。Stripeは最大3週間にわたって決済をリトライしますが、アプリ側では最初の失敗時点でサービス停止の扱いになります。

ビジネスへの影響

1月の解約扱いリスト9名中8名がこの問題に該当。決済エラーが退会としてカウントされ、入退会数に大きな違算が出ています。

舛永さんからの要件

初回の決済失敗から1ヶ月はサービス利用を継続できる仕様が望ましい。クレジット決済再開に約2ヶ月要するケースがあり、即停止は顧客体験として問題。

原因

Stripeから「決済が失敗しました」というイベント通知がアプリに届く設定になっていませんでした。アプリ側にはその通知を受け取った際にサービス期限を延長するコードが存在しますが、通知自体が届かないため一度も実行されていない状態です。

現状の動作(修正前)
月額決済の時期が来る

Stripeがクレジットカードへの課金を試みる

決済が失敗する

カード期限切れ、残高不足など

アプリに通知が届かない

「決済失敗」の通知がStripe側で未設定のため、アプリは失敗を検知できない

利用期限が延長されない → サービス停止

利用期限がそのまま切れてサブスク無効に。ユーザーは退会扱いになる

修正後の期待動作
月額決済の時期が来る

Stripeがクレジットカードへの課金を試みる

決済が失敗する

カード期限切れ、残高不足など

アプリが決済失敗を検知

Stripeからの通知を受け取り、利用期限を1ヶ月延長する

サービス継続

ユーザーは猶予期間中もサービスを利用できる。その間にStripeが自動リトライ

リトライ成功 → 通常状態に復帰

カードが有効に戻れば決済成功。失敗情報がリセットされ通常のサブスクに戻る

修正内容

Stripeの管理画面で「決済失敗」の通知をアプリに送る設定を追加します。アプリ側にはこの通知を受け取って利用期限を延長するコードが既にあるため、コードの新規開発は不要です。

ただし、既存コードにデータ形式の不整合が見つかっており、利用期限の延長は行われるものの、計算値に若干のズレが生じる可能性があります。この問題は別途調査・対応します。

今回の通知設定追加によって、これまで実行されていなかったコードが初めて動作します。このタブでは、そのコードが何をするのかを説明します。

全体像 ― 決済失敗時にアプリが行う処理

Stripeから「決済が失敗しました」という通知が届くと、アプリは以下の3つの処理を順に実行します。

1. どのユーザーの決済が失敗したかを特定する

Stripeの顧客IDからアプリ上のユーザーを照合する

2. サブスクリプションの利用期限を延長する

現在の請求期間の終了日から1ヶ月先まで利用期限を延ばす。同時に、失敗日時・リトライ回数・エラーの種類を記録する

3. 支払いステータスを「失敗」に更新する

ユーザーの最新の支払い状態を「失敗」として記録する

これにより、決済が失敗してもユーザーは猶予期間中サービスを利用でき、その間にStripeが自動的に決済をリトライします。

処理のパターン

決済の失敗・成功にはいくつかのパターンがあり、それぞれ異なる処理が実行されます。

A
初回の決済失敗
月次課金が初めて失敗したとき

ユーザーのサブスクリプションに対して、以下の情報が記録されます。

利用期限 → 現在の請求期間の終了日 + 1ヶ月に延長
失敗日時 → この時点の日時を記録(以後のリトライでは上書きされない)
リトライ回数 → 1回目として記録
エラーの種類 → カード期限切れ、残高不足などの情報を記録
イベントID → 同じ通知の二重処理を防ぐためのID

サブスクの履歴がまだ存在しないユーザーの場合は、新しくサブスクのレコードが自動で作成されます。

B
2回目以降のリトライ失敗
Stripeが自動リトライしたが、再び失敗したとき

リトライ回数が加算されます(最大4回まで)。利用期限も再計算されます。

ポイントとして、最初に決済が失敗した日時は上書きされず保持されます。これにより「いつから決済が止まっているか」を後から追跡できます。

また、Stripeが同じ通知を重複して送ってきた場合は、イベントIDの照合で自動的にスキップされ、データが二重に更新されることはありません。

C
リトライが成功した場合
カードが有効に戻り、Stripeのリトライで決済が成功したとき

決済が成功すると、失敗に関する情報がすべてリセットされます。

失敗日時 → クリア
リトライ回数 → クリア
エラーの種類 → クリア
支払いステータス → 「成功」に更新

ユーザーは通常のサブスク状態に復帰し、次の月次課金も通常通り行われます。

D
通常の月次更新(決済成功)
毎月の自動課金が正常に成功したとき

決済が成功すると、利用期限が次の請求期間の終了日に更新されます。既にサブスクが有効な場合は、既存のレコードの利用期限を延長します。

もし退会処理されていたユーザーが再度決済成功した場合は、退会フラグが自動で解除され、端末も再有効化されます。

処理で更新されるデータ一覧

以下は検証時にエンジニアが確認するデータ項目です。参考として記載します。

サブスクリプション情報
利用期限 決済失敗時に1ヶ月延長される / 決済成功時に次の期間終了日に更新される
失敗日時 初回失敗時に記録され、以後のリトライでは上書きされない。成功時にクリア
リトライ回数 失敗のたびに加算(最大4回)。成功時にクリア
エラーの種類 カード期限切れ、残高不足など。成功時にクリア
イベントID Stripeからの通知の識別子。同じ通知の二重処理を防止する
支払いステータス
ステータス 「成功」または「失敗」。最新の決済結果を反映
ユーザー情報(退会復帰時のみ)
退会フラグ 退会ユーザーが決済成功した場合に解除される
端末の有効化 退会解除と同時に、端末が再び使えるようになる