決済を統合
決済統合は、どのチームも必ず来ることがわかっていながら、誰も喜んで構築しない作業です。プロバイダーの SDK はそれぞれ異なり、Webhook の署名は間違えやすく、エッジケースを1つ見落とせば、支払いが失敗するか、二重請求が発生します。Sun Agent Kit はプロバイダー固有の Webhook ハンドラー、冪等性キー、照合ログを含む完全な本番対応の決済統合をスキャフォールドします。チームは試作品ではなく、動作するチェックアウトを出荷できます。
概要
目的: 決済プロバイダーをエンドツーエンドで統合する: チェックアウトセッション、Webhook ハンドリング、サブスクリプション管理、返金処理
所要時間: 25〜50分(ドキュメント読み込み・ボイラープレート作成・Webhook デバッグを含む手動作業の場合は5〜10時間)
使用エージェント: planner、implementer、tester、reviewer
コマンド: /sk:cook、/sk:scout、/sk:security-scan、/sk:test
前提条件
- Sun Agent Kit がインストール・認証済みであること(インストールガイド)
- 稼働中のバックエンドアプリケーション(Node.js/Express、Python/FastAPI、Laravel、または Spring Boot)
- API キーが利用可能な決済プロバイダーアカウント(
.envに保存し、ハードコードしないこと) - インターネットからアクセス可能な Webhook エンドポイント(ローカル開発には
ngrokなどを使用) paymentsまたはordersテーブルを含むデータベース(不足している場合はエージェントがマイグレーションを作成)
ステップ別ワークフロー
ステップ 1: 既存のコードベースから決済関連コードを調査する
何かを生成する前に、エージェントが既存の状態(カートロジック、注文モデル、部分的な統合など)をマッピングします。
/sk:scout "payment, checkout, order, cart, billing, subscription, invoice"
実行内容: エージェントが以下を実行します:
- コントローラー・モデル・設定内の決済関連パターンをリポジトリでスキャンする
- 統合サーフェスをマッピングする(フレームワーク、ORM、認証方式)
- 既存のもの(注文モデル、カートロジック)と不足しているもの(Webhook ハンドラー、サブスクリプション管理)を特定する
plans/reports/に保存される統合ブループリントを生成する
ステップ 2: 決済プロバイダーを選択して統合を生成する
必要なプロバイダーと決済フローをエージェントに伝えます。
/sk:cook "Stripe payment integration with one-time checkout and subscription support, using Prisma and Express"
実行内容: エージェントが以下を実行します:
- プロバイダー SDK をインストールし、冪等性キーパターンを使用したチェックアウトセッションハンドラーを作成する
- サブスクリプション管理ルート(subscribe、cancel、check status)を生成する
- 主要なイベントタイプの署名検証を含む Webhook ハンドラーを構築する
- サブスクリプションと決済監査ログのデータベースマイグレーションを作成する
- ハッピーパスと失敗シナリオをカバーするユニットテストを作成する
ステップ 3: 第2の決済プロバイダーを追加する(ベトナム向け SePay)
国際市場とベトナム市場の両方にサービスを提供するプロジェクトでは、Stripe に加えて SePay を代替決済手段として追加します。
/sk:cook "Add SePay payment gateway alongside existing Stripe integration. SePay handles VND bank transfers for Vietnamese customers."
実行内容: エージェントが以下を実行します:
- VND 通貨処理と QR コード生成機能を持つ SePay チェックアウトハンドラーを生成する
- HMAC-SHA256 署名検証を含む SePay Webhook ハンドラーを構築する
- 通貨ベースのルーティングロジックを実装する(VND → SePay、それ以外 → Stripe)
- SePay 決済フローのテストを作成する
ステップ 4: Webhook を設定してローカルでテストする
Webhook は本番環境でサイレントに壊れる部分です。エージェントが検証とテストスクリプトをセットアップします。
/sk:cook "Test payment webhooks locally with stripe-cli and verify all event types are handled"
実行内容: エージェントが以下を実行します:
.envのローカル Webhook 設定とシークレットを検証する- 主要なイベントタイプをカバーする Webhook テストスクリプトを生成する
- 各イベントハンドラーが期待するデータベースレコードを作成することを検証する
ステップ 5: 決済コードのセキュリティスキャンを実行する
決済コードは高価値な攻撃対象です。コミット前にフォーカスされたスキャンを実行します。
/sk:security-scan src/payments/ src/webhooks/
実行内容: エージェントが以下を実行します:
- 処理前に Webhook 署名が検証されていることを確認する
- すべてのミューテーションエンドポイントで冪等性キーが使用されていることを確認する
- 生のカードデータが保存またはログ記録されていないことを確認する
- 金額検証がサーバー側で行われていることを確認する(クライアント側の価格を信頼しない)
- 不足しているセキュリティ対策(例: レートリミット)にフラグを立てる
完全な例: ベトナムの EC クライアントが SePay + Stripe のデュアル統合を必要とする
シナリオ
ベトナムのファッション EC クライアントが国際展開を行います。既存の Laravel バックエンドには基本的な代引き払いフローがあります。新しい要件: ベトナムのお客様は SePay 銀行振込(QR コード)で、海外のお客様は Stripe カードで支払います。両方のフローが同じ orders テーブルを更新する必要があり、経営者は単一の照合レポートが必要です。締め切りはスプリント終了、つまり5営業日です。
連鎖コマンド
# Day 1 morning — understand what exists
/sk:scout "payment, order, checkout, cart"
# Day 1 afternoon — scaffold both providers at once
/sk:cook "Dual payment integration for Laravel: Stripe for international customers (USD/EUR), SePay for Vietnamese customers (VND). Shared orders table, unified reconciliation log."
# Day 2 morning — add subscription support (client also sells monthly boxes)
/sk:cook "Add monthly subscription support to Stripe integration — Stripe Billing, plan management, cancellation flow"
# Day 2 afternoon — test webhook handling thoroughly
/sk:test "comprehensive webhook tests for both Stripe and SePay handlers — test idempotency, signature failure, duplicate event rejection"
# Day 3 — security review before demo
/sk:security-scan --full
# Day 4 — generate client-facing integration documentation
/sk:docs "Payment integration guide for client handoff — cover both Stripe and SePay, webhook setup, .env variables, reconciliation query"
結果
4日目までに、クライアントは動作するデュアルプロバイダーのチェックアウト、すべてのエッジケースを処理するテスト済みの Webhook パイプライン、両方の決済ソースを単一のダッシュボードビューに結合する照合クエリを手に入れます。ハンドオフドキュメントには、社内チームが今後統合を管理するために必要なすべての情報が含まれています。
時間比較
| タスク | 手動 | Sun Agent Kit 使用 |
|---|---|---|
| Stripe SDK ドキュメント読み込み + ボイラープレート | 90分 | 数分 |
| チェックアウトセッションとエラーハンドリングの実装 | 60分 | 数分 |
| 署名検証付き Webhook ハンドラーの構築 | 45分 | 数分 |
| SePay API 調査 + 実装 | 90分 | 数分 |
| 決済フローのテスト作成 | 60分 | 数分 |
| 決済コードのセキュリティレビュー | 30分 | 数分 |
| 合計 | 約6時間 | 30分以内 |
ベストプラクティス
1. 金額は必ずサーバー側で検証し、クライアントを信頼しない ✅
エージェントはデフォルトでこのパターンを強制します。チェックアウトセッションは常にクライアントが提供した金額フィールドではなく、データベースの price_id または product_id を使用して価格を導出します。これにより、価格操作攻撃を防ぎます。
2. すべての Webhook 処理に payment_events 監査ログを使用する ✅
スキャフォールドされた Webhook ハンドラーは、受信したすべてのイベントを処理前に payment_events テーブルに書き込みます。これにより、冪等性(処理済みイベント ID のスキップ)、照合トレイル、決済が「謎めいた」理由で確定しない場合のデバッグサーフェスが確保されます。
3. 本番環境で完全な決済ペイロードをログに記録しない ❌
Stripe と SePay のペイロードには、部分的なカード番号や機密の請求情報が含まれる場合があります。生成されたコードはイベントタイプとイベント ID のみをログに記録します。本番環境で Webhook の問題をデバッグするために console.log(event) や Log::debug($event) を追加しないでください。代わりにプロバイダーのダッシュボードを使用してください。
4. ステージング環境でも Webhook 署名検証をスキップしない ❌
ローカルデバッグ時に署名検証をコメントアウトしたくなることがあります。これは最終的に本番デプロイに入り込む習慣を作り出します。常に署名検証を有効にしておき、ローカルテストにはプロバイダーの CLI ツール(例: stripe listen)を使用してください。
トラブルシューティング
問題: Webhook イベントは受信されるが、注文が作成されない(ログにエラーなし)
解決策: 最も一般的な原因は、署名検証に使用される生リクエストボディの Content-Type: application/json が欠落していることです。Express(および多くのフレームワーク)は Webhook ハンドラーが見る前にボディを解析し、HMAC 検証に必要な生バッファを破壊します。生成されたハンドラーは express.raw({ type: 'application/json' }) をミドルウェアとして使用します。Webhook ルートの前にグローバル JSON パーサーが実行されていないことを確認してください。
問題: SePay QR コード決済で Webhook がトリガーされない
解決策: SePay は Webhook コールバック URL をマーチャントダッシュボードに登録する必要があり、HTTPS でなければなりません。ローカル開発では、ngrok トンネル URL が登録されていることを確認してください。ステージングでは、SePay の IP 範囲からサーバーに到達でき、.env の SEPAY_WEBHOOK_SECRET がダッシュボードの値と一致していることを確認してください。
問題: Stripe サブスクリプションキャンセルの Webhook が発火するがユーザーアクセスが取り消されない
解決策: ハンドラーが customer.subscription.updated ではなく customer.subscription.deleted をリッスンしていることを確認してください。期間終了時のキャンセルは cancel_at_period_end: true を含む customer.subscription.updated を発火します。アクセスは current_period_end まで有効であるべきです。生成されたハンドラーは両方のイベントをカバーしています。customer.subscription.updated ブランチを削除していないことを確認してください。
問題: リトライ時に重複注文が作成される
解決策: /sk:cook "Add idempotency key handling to Stripe checkout session creation" を実行して冪等性パターンをスキャフォールドします。Stripe API は Idempotency-Key ヘッダーを受け付けます。sha256(userId + cartId + timestamp_minute) として生成すると、同じ分内のリトライは既存のセッションを再利用します。
次のステップ
- セキュリティ監査・スキャン — 本番公開前に対象を絞った決済セキュリティ監査を実行する
- パフォーマンス最適化 — 決済エンドポイントがトラフィックスパイクでタイムアウトしないようにする
- ドキュメント自動生成 — 決済設定を網羅したクライアントハンドオフドキュメントを作成する
重要なポイント: 決済統合は締め切りのプレッシャー下で手書きするには誤りが多すぎます。エージェントが完全なセキュリティ強化済み統合をスキャフォールドすることで、チームはボイラープレートではなくビジネスロジックに集中できます。