オンライン決済実装研究所
障害運用

Stripe Webhook で起きやすい失敗を運用視点で10個に整理する

Stripe Webhook で起きやすい失敗を、署名検証、再送、冪等性、順不同イベント、監視不足の観点から整理します。

この記事の要点

Webhook障害の多くは、イベントを一回だけ来る前提で処理していることが原因です。署名、保存、冪等性、再処理導線までを最初から含めると、後の運用が大きく楽になります。

公開日: 2026/4/10 更新日: 2026/4/12 著者: オンライン決済実装研究所 編集部

結論

Webhook を「通知」ではなく 非同期の事実ストリーム として扱うと設計が安定します。

Stripe の公式仕様上も、署名検証、raw body、再送、手動再処理は避けて通れません。
タイトル通り、実務で本当に多い失敗を 10 個に分けて整理します。

起きやすい失敗 10 個

  1. 署名検証を入れていない
  2. raw body を壊してから検証している
  3. CLI 用 secret と Dashboard 用 secret を混同している
  4. イベント保存前に副作用を起こしている
  5. event ID 単位の重複防止がない
  6. 同期レスポンスと Webhook の両方で注文確定している
  7. イベントが順番通りに来る前提で内部状態を組んでいる
  8. 遅延決済のイベントを処理対象に入れていない
  9. 手動再処理導線がなく、障害時に API と SQL を直叩きする
  10. Connect で「自分のアカウント用」と「接続アカウント用」の Webhook を分けていない

最初に潰すべき 4 つ

1. 署名検証を入れていない

Stripe は Stripe-Signature ヘッダーでイベントを検証できます。
これを外すと、到達した JSON をそのまま信じる設計になります。

2. raw body を壊している

Stripe は 生のリクエスト本文 で署名検証します。
express.json() で先に JSON へ変換すると、同じ内容に見えても検証に失敗します。

3. イベント保存前に副作用を起こしている

メール送信、在庫引当、権限付与を先にやると、途中失敗時に再実行できません。
まず event ID と payload を保存して、その後に業務処理へ進める方が安全です。

4. event ID 単位の重複防止がない

Stripe は未配信イベントを自動再送します。
同じ event.id を二度処理しても副作用が一回で止まるようにしないと、二重反映が起きます。

実装順のおすすめ

Step 1: 受信して署名検証し、まず保存する

受信直後に業務処理を全部やるより、受けたイベントをまず保存してから後段に渡す方がトラブルに強いです。

保存時点で最低限持ちたいもの:

Step 2: 副作用は一箇所に寄せる

メール送信、在庫反映、契約更新などの副作用が複数箇所に散ると、再送時に事故ります。

Step 3: 「未処理」「処理中」「処理済み」を持つ

Stripe の手動再処理ガイドでも、処理中・処理済みの記録を DB に持って重複を防ぐ考え方が出てきます。

Step 4: 運用画面を先に作る

本番で強いのは、イベント単位で「受信」「処理済み」「失敗」「再実行」を見られる画面です。

見落としやすい失敗

順不同イベントを直列フローだと思い込む

たとえば invoice.paid より先に customer.subscription.updated を見たり、payment_intent.succeeded より先に周辺イベントを見ることがあります。
イベントの到着順ではなく、取得したオブジェクトの現在状態 を正にしてください。

success ページを正とする

Checkout の戻り先ページは UI の完了表示であって、バックエンドの確定処理そのものではありません。
同期レスポンスで確定し、さらに Webhook でも確定すると二重計上の温床になります。

Connect の Webhook を普通の Webhook と同じだと思う

Connect では「自分のアカウントのイベント」と「接続アカウントのイベント」の 2 系統があります。
接続アカウントのイベントにはトップレベルの account プロパティが付きます。

再送を待つだけで手動回復手順がない

Stripe は未配信イベントを最大 3 日程度自動再送しますが、それとは別に undelivered events を手動処理する手順を用意しておくべきです。

監視で最低限ほしいもの

項目目的
受信件数受信停止の検知
失敗件数異常増加の検知
再送件数下流不安定の検知
最終処理時刻遅延の検知
livemode 別件数test / live 混入の検知
account 別失敗率Connect 事故の局所化

併読推奨

よくある質問

Webhook は順番通りに来る前提でよいですか?

その前提は危険です。内部状態をイベント順に依存させすぎない方が安全です。

次に読む記事

実装ガイド

PaymentIntent の状態遷移を実装事故ベースで理解する

PaymentIntent の状態遷移を、作成、認証、確定、失敗、再試行の流れに沿って整理します。Webhook 連携の観点にも触れます。

PaymentIntent は単なる決済オブジェクトではなく、決済の途中状態を扱う設計の中心です。状態遷移を理解しておくと、二重計上や webhook の処理漏れをかなり防げます。

2026/4/10 Stripe / PaymentIntent / Webhook
実装ガイド

決済 API の冪等性を実装事故ベースで理解する

Stripe を中心に、冪等性キーが必要な理由、注文 ID とどう結びつけるか、再送やタイムアウト時に何を保証できるかを整理します。

決済 API の事故で多いのは、通信失敗後の再実行を『もう一度 POST するだけ』で済ませることです。冪等性キーを内部注文 ID と束ねると、二重課金と調査コストを大きく減らせます。

2026/4/12 Stripe / 冪等性 / 決済API
実装ガイド

Stripe で決済機能を実装する手順をサンプルコード付きで追う

Checkout Sessions と Webhook を使って、商品選択から決済完了反映までを Node.js サンプルコード付きで段階的に説明します。

最初の実装は hosted checkout がいちばん事故りにくいです。金額は必ずサーバーで決め、注文確定は Webhook を正とし、フロントはリダイレクトと結果表示に責務を絞ると安定します。

2026/4/12 Stripe / Checkout / Webhook