Blog
未払い請求書をStripe外で回収した場合に、Webhookがどんな動きをするかを調べてみた
Stripeで管理している未払い請求書を、クレジットカード以外の方法(PayPalや現金など)で回収した場合、システム側でどのようにデータ連携を行えばよいのでしょうか。
本記事では、テスト環境を用いて実際に請求書を手動で支払い済みに変更し、その際に送信されるWebhookイベントの詳細を調査しました。調査の結果、invoice.paidイベントを監視することで、決済手段によらず統一的な支払い完了処理が実装できることが確認できました。また、invoice.updatedイベントのprevious_attributes属性を確認することで、外部決済と通常決済を識別し、運用フローに応じた柔軟な処理の実装方法についても解説します。
テスト環境で、未払い請求書の回収を試してみる
テスト環境にて未払いの請求を用意しました。今回はカードの決済が拒否されるクレジットカード番号(4000000000000002)を決済手段に設定しています。

Stripe の外でこの請求を回収できた場合、[顧客に請求]ボタンの右側にある[…]ボタンをクリックします。
すると[インボイスのステータスを変更]というメニューが表示されますので、これをクリックしましょう。

請求書のステータスを手動で変更する画面が開きました。ここでは請求書が「外部で決済されたので完了とする」や「誤って作成されたので無効化する」などの設定変更が行えます。
今回はStripeの外で回収ができた想定ですので、[支払い済み]を選びましょう。また、[内部メモ]に「いつ・どこで・誰がどうやって回収したか」を記録しておきます。

これで請求書が支払い済みステータスに変わりました。

内部メモを残しておくことで、後から支払い履歴などを調査する場合に役立ちます。

このようにダッシュボード上で簡単に請求書の手動処理が実施できます。もしクレジットカードでの支払いが上手くいかず、「PayPalなどで送金したい」と連絡があった場合でも、Stripe上の処理自体はとてもシンプルにできそうです。
Webhookでのデータ連携について深掘りする
ECやSaaSを構築している場合に気になるのは、データ連携です。アプリケーション側では支払いが完了するまで、発送フローの一時停止や機能の利用停止などが行われているでしょう。これらを再開するためには、Stripeから支払いが完了したというイベントがWebhookにて送られる必要があります。
ワークベンチを利用して調査したところ、payment_intent.canceled / invoice.updated / invoice.paidの3イベントが送信されていることがわかりました。

外部で決済が行われたことでStripe上での決済処理が中止されています。そのため、payment_intent.canceled が送信されていました。また、支払い方法や決済ステータスが変更されていることが、invoice.updated イベントの発火理由です。そして支払いが完了したとStripeが判断したイベントとして、invoice.paidが送信されています。
このことから、invoice.paidによる支払い完了・回収成功状況の監視を実施することで、Stripe外での決済についてもシステムとのデータ連携が行えそうです。
invoice.updatedイベントで変更される具体的な内容
invoice.updatedイベントのペイロードには、previous_attributesフィールドが含まれており、どの項目が変更されたかを正確に把握できます。今回のテストで確認したところ、請求書を手動で支払い済みに変更した際には、8つの属性が更新されていました。
最も重要な変更は、paid_out_of_bandがfalseからtrueに変更されている点です。この属性がtrueになることで、Stripe外での支払い処理が行われたことが明確に記録されます。また、statusがopenからpaidへ変更され、status_transitions.paid_atに支払い完了のタイムスタンプが記録されます。
一方で、自動決済に関連する属性も同時に変更されています。chargeとpayment_intentがnullに設定され、auto_advanceがfalseに変更されます。これは、Stripe外での決済が完了したため、Stripe側での自動決済処理が不要になったことを示しています。具体的には、以前はchargeオブジェクトIDとpayment_intentオブジェクトIDが設定されていましたが、これらが削除されることで、Stripeプラットフォーム上での決済処理パイプラインから切り離されたことが明示されます。
さらに、closedフィールドがfalseからtrueに変更されることで、この請求書に対する追加の変更や処理が行えなくなります。これにより、誤って二重に決済処理が実行されるリスクを防ぐことができます。
まとめ
Stripeの請求書を外部で回収した場合でも、適切なWebhookイベントが送信されることが確認できました。invoice.paidイベントを監視することで、決済手段によらず統一的な支払い完了処理が実装できます。
システム設計の観点では、paid_out_of_band属性を活用して外部決済を識別し、必要に応じて処理を分岐させることが推奨されます。これにより、クレジットカード決済が失敗した顧客に対しても、現金やPayPalなど代替手段での支払いを柔軟に受け付けられる体制を構築できます。また、previous_attributes属性を詳細に分析することで、どのような状態変化が発生したのかを正確に把握し、適切なログ記録やアラート設定を行うことも可能です。
実運用においては、invoice.paidイベントとinvoice.updatedイベントの両方を適切に処理するWebhookエンドポイントを実装し、冪等性を保証することで、安定したシステム運用を実現できるでしょう。
