支払いは成功したのに有料化されないとき、最初の30分でやること
Stripeで支払い成功なのに有料化されないとき、最初の30分で“イベント/配信/処理”を切り分けて復旧する手順です。
Stripeで「支払いは成功した(カード決済は通った)のに、ユーザーが有料にならない/機能が解放されない」というときは、まず (1) Stripe側で“成功”が何を指すか と (2) アプリ側が“有料化”を確定するトリガー を30分で固定すると、最短で復旧できます。
最初に結論
- まず「どの画面の“成功”なのか」を固定します(Checkout完了なのか、PaymentIntent成功なのか、Invoice支払いなのか)。
- 次に「どのイベントで有料化しているのか」を固定し、Stripe Dashboard の Events と Webhook配信ログ で “イベントはある/ない・届いている/いない・処理できている/いない” を分けます。
- 最後に、アプリ側の 冪等性(重複イベント) と 遅延/再送(retries) を前提に「有料化が“たまに”抜ける」原因を潰します。
最初の30分でやること
1) “成功”の定義を固定する(5分)
最低限この3点をメモします。
- 何のフローか(例: Checkout / Payment Element / 既存顧客の請求/更新)
- どのIDが手元にあるか(例:
cs_.../pi_.../in_.../sub_.../cus_...) - テスト/本番どちらか(Stripe Dashboardのモード + アプリのAPIキー)
「成功した」の根拠がメールや画面キャプチャだけの場合は、Stripe Dashboard で対象IDを検索し、Stripe側で成功が確定しているか を先に確定します。
2) Stripe側のイベントが発生しているか(Events)(5分)
Stripe Dashboard の Events で、対象IDに紐づくイベントを確認します。
よく使われる“有料化トリガー候補”:
- Checkout:
checkout.session.completed - 1回払い:
payment_intent.succeeded - 請求(Invoice):
invoice.paid - サブスク作成:
customer.subscription.created/customer.subscription.updated
ここで確定したいこと:
- 期待しているイベントが 存在するか
- イベントが テスト/本番のどちらで起きているか
- イベントの
data.object(Checkout Session / PaymentIntent / Invoice 等)に、期待する金額や顧客が入っているか
イベントが無い場合は、Webhook以前の問題(決済未完了・支払い失敗・モード取り違え・別アカウント)である可能性が高いです。
3) Webhookが届いているか(Delivery attempts)(5分)
Stripe Dashboard の Webhook Endpoint の 配信ログ を見て、対象イベントが送られているかを確認します。
- 送信先URLが“今の本番URL”か(www有無/サブドメ/パス/古い環境)
- Endpointが無効化されていないか
- 必要なイベントがListen対象に入っているか
読み方(ざっくり):
- 配信ログがない → イベント未発生/モード違い/別アカウントの可能性が高い
- 4xx → アプリが拒否(ルーティング/署名検証/ボディ処理)
- 5xx → アプリ例外(DB/外部API/バグ)
- タイムアウト → 同期処理が重い(キュー化/非同期化/2xxで速く返す)
4) “受け取ったのに反映されない”を疑う(アプリ側)(10分)
Webhookが2xxで返っているのに有料化されない場合、ありがちな原因は次のどれかです。
- 有料化の判定が “別イベント” に依存している(例:
payment_intent.succeededを見ているが実際はinvoice.paidが必要) - 冪等性がない(再送や重複イベントで状態が巻き戻る/競合する)
- Webhook処理が重く、途中で落ちる(2xxを返す前に例外、もしくはDB/外部APIで失敗)
- 同期の順序問題(例:
checkout.session.completedより前に別イベントが届く/逆順に処理される) - 環境の取り違え(Webhookは本番、DBは別環境、またはその逆)
この10分で最低限やること:
- 1イベントにつき1行でよいので、イベントID(
evt_...)と処理結果(成功/失敗/重複) がログに残るか - DBに「このユーザーをいつ有料にしたか」の記録が残るか(最終更新時刻、決済ID/イベントID)
- アプリの “有料化の条件” がどれかを言語化できるか(例:
invoice.paidを受けてstatus=activeにする)
5) “たまに抜ける”症状の典型パターン(5分)
- 重複イベントで二重実行 → 片方が失敗してロールバック/競合
- “成功”の種類が複数ある(Checkout / 請求 / 更新) → 一部の経路だけイベントを見ていない
- Webhookの再送が走る(遅延/障害) → 受信側が再実行に耐えない
「全員がダメ」より「一部だけ抜ける」ほうが、アプリ側の冪等性・順序・イベント網羅の問題であることが多いです。
SiteOpsで最短にする
複数サービス運営では「支払い成功」でも、Stripeの設定・イベント・実装がサイトごとに違うことがよくあります。SiteOpsはサイト別に “いつから/何が変わったか/どのイベントが欠けているか” を並べて、復旧の優先順位と止血の順番を早く固定します。
次に読む
- /media/stripe-webhook-events-not-firing-first-30-minutes
- /media/stripe-webhook-delivery-failure-first-30-minutes
- /media/stripe-webhook-signature-verification-failed-first-30-minutes
相談する(SiteOps)
- まずは ダッシュボード で、影響が出ているサイト(どの異常から触るべきか)を先に列挙します
- 相談したい場合は お問い合わせ から状況を送ってください(止血の順番を一緒に整理できます)
- 料金と導入の流れは 料金ページ にまとめています
参考にした一次情報
この記事を書いた人
川原
SiteOps編集チームの公開窓口として、検索、アクセス、収益データをもとにした運営判断の知見をまとめています。
関連記事
次にやること
複数サイトの検索、アクセス、収益データをまとめて見直すなら、SiteOpsのダッシュボードでサイト別に確認できます。
料金を見る相談したい / お問い合わせ