結論
決済機能は「実装できたら終わり」ではなく、本番で壊れたときにどう直すかまで含めて完成 です。
特に VibeCoding では、API をつなぐところまでは早くても、その後の Webhook 再送、返金、照合、問い合わせ対応 が抜けがちです。
最低限そろえるべき運用の土台
| 項目 | ないと何が起きるか |
|---|---|
| 注文状態の設計 | paid と refunded の区別が曖昧になり、社内説明が崩れる |
| 外部 ID の保存 | ダッシュボード上の決済と自社注文を結びつけられない |
| イベント保存 | Webhook 再送や障害再処理ができない |
| 再実行導線 | 一度失敗した処理を手作業でしか直せない |
| 監視 | 決済停止に気づくのが数時間遅れる |
| 返金手順 | CS と経理で認識がズレる |
| 照合手順 | 入金と注文の不一致を放置しやすい |
「イベントを保存して後からやり直せる」だけで、運用の強さはかなり変わります。
本番前チェックリスト
1. 状態を最初に決める
少なくとも以下は分けて持った方が安全です。
pendingpaidfailedcanceledrefundedpartially_refunded
支払い成功と売上確定、返金完了と顧客通知完了を同じ状態にすると、運用で必ず詰まります。
2. 外部 ID を必ず保存する
最低限、以下を自社 DB に残してください。
- 自社注文 ID
- 決済代行側の注文 / セッション / PaymentIntent / Capture ID
- 顧客 ID
- Webhook event ID
- 返金 ID
これがあると、障害時に「Stripe 側では成功、内部注文では pending」のような不整合を追えます。
3. Webhook を証跡として保存する
Webhook は通知ではなく、非同期の事実ログ として扱います。
保存しておく情報の例:
- event ID
- event type
- 受信時刻
- 署名検証の結果
- 処理結果
- エラーメッセージ
- 再実行回数
Stripe は Webhook 配信失敗時に再送します。
保存していないと、失敗したイベントを後から安全に再処理できません。
4. 冪等性キーを使う
重複課金や二重 capture を避けるには、各社の冪等性の仕組みを使うべきです。
| サービス | 代表的な仕組み | 覚えておくこと |
|---|---|---|
| Stripe | Idempotency-Key | create / update の再試行で同じ結果を返せる |
| PayPal | PayPal-Request-Id | Orders API などの POST で重複実行を抑える |
| Square | idempotency_key | CreatePayment などで必須になる場面がある |
初学者ほど、通信タイムアウト時に「もう一度 POST する」だけの実装になりがちです。
このとき冪等性がないと、決済だけ二重で成功する事故が起きます。
見落としやすい運用ポイント
success ページと入金確定は別物
ユーザーが success ページを見たことと、内部状態を paid にしてよいことは同じではありません。
同期レスポンスと Webhook の責務を混ぜないでください。
遅延決済は「後から成功する」
銀行振込、コンビニ、口座振替系は、決済完了まで時間差が出ることがあります。
カードだけの感覚で設計すると、「今はまだ processing」を扱えずに破綻します。
3Dセキュアは追加入力が必要なことがある
たとえば PAY.JP の 3Dセキュアでは、名義とメールまたは電話番号のような追加項目が必要です。
決済 UI の見た目だけ先に作ると、認証フロー直前で必要項目が足りなくなります。
返金は「Stripe で返したら終わり」ではない
返金したら、最低でも以下を反映する必要があります。
- 内部注文状態
- 顧客への通知
- 会計 / 経理向けの記録
- ライセンスや利用権限の停止
監視で最低限ほしいもの
| 指標 | 目的 |
|---|---|
| 決済成功率 | 失敗増加の早期検知 |
| Webhook 失敗率 | 非同期連携の異常検知 |
| Webhook 最終受信時刻 | 受信停止の検知 |
| 返金件数 | 障害や CS 増加の把握 |
| pending 滞留件数 | 確定漏れや処理漏れの発見 |
アラートは Slack でもメールでも構いません。
重要なのは、誰が見て、何分以内に何をするか が決まっていることです。
障害時の初動
- 同じ副作用が二重実行されないように処理を止める
- 外部 ID と内部注文 ID の対応を確認する
- 保存済みイベントから再処理できるか確認する
- 返金が必要か、顧客通知が必要かを切り分ける
- 原因が分かるまで手動オペの条件を明文化する
この初動手順がないと、障害そのものより 人の判断のブレ で被害が広がります。
小規模でも作っておきたい運用画面
- 注文を ID で検索できる
- 決済事業者側の ID を見られる
- 受信した Webhook 一覧を見られる
- 失敗イベントを再処理できる
- 返金履歴を確認できる
最初は簡易な管理画面でも十分です。
重要なのは「障害時に SQL を直接叩かなくても状況把握できる」ことです。
併読推奨
- Stripe Webhook で起きやすい失敗を運用視点で10個に整理する
- PaymentIntent の状態遷移を実装事故ベースで理解する
- Stripe で決済機能を実装する手順をサンプルコード付きで追う
よくある質問
決済実装で一番先に用意すべき運用項目は何ですか?
注文状態の設計と、Webhook イベントを保存して再実行できる仕組みです。
返金は管理画面から手でやれば十分ですか?
少量なら可能ですが、内部注文との整合性、会計、顧客通知まで考えると記録の一元化が必要です。
冪等性は Stripe だけの話ですか?
いいえ。Stripe、PayPal、Square など主要な決済 API でそれぞれ重複実行を防ぐ仕組みがあります。