Sausage Erectos X Stripe Connect統合の地獄

Stripe Connect地獄の7層――マーケットプレイス決済実装記

Stripe Connectの実装は、ダンテの「神曲」における地獄篇のように階層的な苦難で構成されている。Sausage Erectosの決済基盤を構築する過程で遭遇した7つの層を、コード例とともに記録する。

第1層:アカウントタイプの選択

Stripe ConnectにはStandard、Express、Customの3タイプがある。Standardは売り手が自分のStripeアカウントを持つ方式で、Expressはプラットフォームが管理するダッシュボードを提供する。Sausage Erectosでは工房がすでにStripeアカウントを保有していたためStandardを採用した。この選択が後の実装難度を大きく左右する。

第2層:OAuth認証フローの実装

Standardアカウントの接続にはOAuth 2.0フローが必要だ。redirect_uriを設定し、ユーザーをStripeの認証ページに誘導し、戻ってきたauthorization_codeをサーバー側でアクセストークンに交換する。redirect_uriのドメインがStripeダッシュボードの設定と1文字でも異なるとエラーになる。開発中はlocalhostとngrokのURLを行き来する羽目になった。

第3層:手数料計算ロジック

application_fee_amountの計算は一見単純だが罠がある。税込価格に対してプラットフォーム手数料率(例:30%)を掛ける。残りの70%が接続先アカウントに渡る。しかし小数点の丸め処理を誤ると1円の差異が蓄積し、月末の精算で不整合が発生する。Math.roundで整数に丸めることを徹底した。

第4層:テストモードのカード番号

テストモードでは4242 4242 4242 4242がデフォルトの成功カードだ。4000 0000 0000 9995で残高不足を、4000 0000 0000 0069で期限切れをシミュレートできる。3Dセキュア認証のテストには4000 0027 6000 3184を使う。これらの番号を暗記するまでに何十回もテスト決済を繰り返した。

第5層:Webhookの署名検証

Stripeからのwebhookイベントはwhsec_で始まるシークレットキーで署名検証する。stripe.webhooks.constructEventにrawBody、署名ヘッダー、シークレットを渡す。ここで重要なのはbodyをパース前のraw状態で渡すことだ。Express.jsonミドルウェアの後に配置すると署名検証が必ず失敗する。この1点で丸2日を費やした。

第6層:テストからライブへの切り替え

テストモードとライブモードではAPIキーが完全に別物だ。sk_test_からsk_live_に、pk_test_からpk_live_に変わる。環境変数の切り替え漏れが1箇所でもあると、テストモードのリクエストがライブモードに飛ぶ(またはその逆)。デプロイスクリプトで全環境変数の整合性チェックを自動化した。

第7層:返金処理

Connect経由の返金はさらに複雑だ。プラットフォーム手数料を返金するかどうかを明示的に指定する必要がある。refund_application_feeパラメータをtrueにしないと、手数料だけプラットフォームに残り、顧客は全額返金されたと思っているのに接続先アカウントが損をするという状況が生まれる。

Stripe Connectの実装は地獄だが、一度構築すれば堅牢な決済基盤になる。ドキュメントを3回読み、テストを100回実行し、本番で祈る――それがConnect実装者の日常だ。

テストモードとライブモードの罠

APIキーの切り替え

Stripe Connectの開発で最もハマったのは、テストモードとライブモードの切り替えだ。テスト環境では全て動くのに、ライブに切り替えた瞬間に動かなくなる。

原因はシンプル。テスト用APIキー(sk_test_…)とライブ用APIキー(sk_live_…)は完全に別のキーだ。.envファイルを書き換え忘れると、テストモードのConnectアカウントにライブモードでアクセスしようとしてエラーになる。

Webhookの署名検証

Stripeからのwebhookは署名(whsec_…)で検証する。この署名もテスト用とライブ用で異なる。署名検証が失敗すると、決済は成功しているのにDBに注文が記録されない── 最悪のバグだ。

返金処理の実装

Connect経由の返金は通常の返金より複雑だ。出品者の取り分をどう処理するか。Stripeの公式ドキュメントを3回読み、Stack Overflowを5回検索し、AIに10回聞いて、やっと正しい実装に辿り着いた。

APIは「作る」より「使う」方が難しい。ドキュメントを3回読め。

本番切り替え時の事故

テスト→ライブの落とし穴

Stripe Connectで最も危険な瞬間は、テストモードからライブモードに切り替える時だ。Sausage Erectosでは、以下の手順で切り替えた。

  1. .envのAPIキーをsk_test_…からsk_live_…に変更
  2. Webhook Secretをテストからライブ用に変更
  3. Connect先のアカウントIDは同じ(テストとライブで共通)
  4. PM2でサーバーを再起動

手順3が落とし穴だった。テスト環境で作ったConnectアカウントとライブ環境のConnectアカウントは実は別物だった。切り替え後、最初の決済で「The provided key does not have access to account」エラーが発生。原因の特定に3時間かかった。

教訓

Stripe Connectの切り替えチェックリスト: APIキー、Webhook Secret、Connectアカウント、商品ID、価格ID── 全てテストとライブで別物だと認識すること。

← ブログ一覧に戻る