Stripe セットアップ
Stripe Checkout を使った決済と、Webhook によるクレジット付与の最終確定。環境変数、セッション作成、コールバック処理、署名付き Webhook の扱いを解説します。
概要
このテンプレートは Stripe Checkout で決済し、支払い後にクレジット残高を付与します。
- UI:
/[locale]/pricing
は TypeScript の設定からプランを表示。 - セッション作成:
POST /api/checkout
→ Stripe にリダイレクト。 - リダイレクト: 成功後に
/api/pay/callback/stripe
(GET)。 - 最終反映: Stripe の Webhook が
/api/pay/webhook/stripe
(POST) に届き、注文をpaid
にしてクレジットを付与。
ソース・オブ・トゥルースは Webhook です。コールバックは画面遷移のみ。
クイックスタート資料
- Stripe: はじめに — https://docs.stripe.com/get-started
決済ゲートウェイ 101
決済ゲートウェイとは?
決済ゲートウェイは、クレジット/デビットカード、デジタルウォレット、銀行振込などの電子決済を処理・認可するオンラインの仲介サービスです。実店舗のカードリーダーのオンライン版に相当し、取引を安全に検証して承認/拒否します。
2025 年には世界の EC 売上が約 7.4 兆ドルに達すると予測されています。滑らかで安全なチェックアウトは、顧客体験やコンバージョン、セキュリティと信頼の向上に直結します。
どのように機能するか
- 購入 : ユーザーがチェックアウトで支払い情報を入力。
- 暗号化と送信 : サイトがデータを暗号化してゲートウェイへ送付。
- 転送 : ゲートウェイが暗号化データを決済プロセッサに転送。
- 連携 : プロセッサが発行銀行に認可を依頼。
- 承認/拒否 : 資金状況やセキュリティ検査に基づき銀行が判断。
- 応答返送 : 判断がプロセッサ→ゲートウェイへ戻る。
- 完了 : 承認なら確認、拒否ならエラーをユーザーに表示。
- 資金決済 : 承認取引はアクワイアラ経由で貴社口座に入金。
これらは自動化され、通常は数秒で完了します。
決済ゲートウェイを統合する手順
- プロバイダ選定 : 手数料、対応決済、セキュリティ、プラットフォーム互換性。
- マーチャント口座 : Stripe など一体型もあれば、別途必要な場合も。
- API キー取得 : サイト/アプリとゲートウェイを認証する鍵。
- 実装 : プラグイン(Shopify/WooCommerce)またはカスタム実装。Stripe の API は特に扱いやすいです。
- サンドボックスで検証 : テスト環境・テストカードで動作確認。
- 本番化 : ライブキーに切替え、稼働を監視。
エンドポイント
/api/checkout
(POST):src/data/pricing.ts
を元に検証し、Checkout セッションを作成、注文をcreated
で保存。/api/pay/callback/stripe
(GET): Stripe からのリダイレクト用。最終処理は行いません。/api/pay/webhook/stripe
(POST): 署名検証後、checkout.session.completed
を処理して付与。
クレジットの流れ
- セッションのメタデータから
order_no
を取得。 - 注文を
paid
に更新し、決済情報を保存。 credits
に正の行を追加(order_pay
)。
必要な環境変数
STRIPE_PRIVATE_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_WEB_URL=http://localhost:3000
NEXT_PUBLIC_PAY_CANCEL_URL=/pricing
NEXT_PUBLIC_PAY_SUCCESS_URL=/pricing
NEXT_PUBLIC_PAY_FAIL_URL=/pricing
ローカル Webhook 設定
stripe login
stripe listen --forward-to localhost:3000/api/pay/webhook/stripe
# 表示された whsec を .env に設定
stripe trigger checkout_session_completed
動作確認
- サインアップ/ログイン。
/[locale]/pricing
でプランを選択。- テストカード
4242 4242 4242 4242
で決済。 - Webhook が注文確定とクレジット付与を実行。
/[locale]/credits-test
で残高を確認。
Stripe 統合ガイド(ハイレベル)
以下の手順で素早く Stripe を統合できます:
- アカウント作成:Stripe に登録し、事業情報と入金口座を設定。
- API キー取得:ダッシュボード → Developers で公開鍵/秘密鍵を取得。
- ライブラリ導入:公式 SDK(JavaScript/TypeScript、Ruby、Python など)。
- フロント実装:Stripe.js と UI コンポーネント(Elements/Payment Element)やプラグインで安全にカード情報を収集。
- サーバ実装:秘密鍵で Stripe を初期化し、PaymentIntent/Checkout Session を作成するエンドポイントを用意。
- 情報収集:生カードを保持せず、Stripe のコンポーネントで取得。
- サーバ送信:HTTPS 経由で意図情報を安全に送信。
- サーバ処理:SDK で PaymentIntent/Checkout Session を作成。
- 応答処理:DB を更新し、成功/失敗をクライアントへ返却。
- エラー/例外:残高不足、期限切れ、3DS、リトライ等を考慮。
- 徹底テスト:テストモード、Webhook、テストカードで各パターン検証。
- 本番移行:テスト鍵→本番鍵、必要な支払い方法を有効化し監視。
ヒント:公式ガイド — https://docs.stripe.com/get-started
実装メモ
- プラン:
src/data/pricing.ts
に定義(型安全)。 handleCheckoutSession
は一括・サブスク両対応(サブスクは最新請求書から PaymentIntent を取得)。
請求とサブスクリプション
カスタマーポータル
Stripe の Customer Portal を有効化し、顧客が行える操作(解約/再開、カード更新、請求書閲覧)を設定します。
本テンプレートには以下を用意しています:
- API:
GET /api/billing/portal
— ポータルセッションを作成して Stripe にリダイレクト - UI:
/:locale/account/billing
— 「Manage billing」ボタンでポータルを開く
実装箇所:
- API ルート:
src/app/api/billing/portal/route.ts
- ログイン中ユーザーのメールで Stripe Customer を検索/作成
return_url
を/:locale/account/billing
に設定
UI(Server Component):
src/app/[locale]/account/billing/page.tsx
から/api/billing/portal?locale=<locale>
へリンク
督促(支払い失敗)
Webhook invoice.payment_failed
で、支払い方法の更新を促すメール(Resend)を送信します。
- テンプレート:
src/services/email/templates/payment-failed.tsx
- 送信関数:
sendPaymentFailedEmail()
(src/services/email/send.ts
) - Webhook 実装:
src/app/api/pay/webhook/stripe/route.ts
Stripe CLI でのテスト:
stripe trigger invoice_payment_failed
備考:メールに /:locale/account/billing
へのリンクを含め、アプリからポータルを開けます。
製品と価格(Stripe)
Stripe は「販売するもの(製品)」と「価格設定(価格)」を分離しています:
- 製品(
prod_...
):名称・説明、カタログ用メタデータ。1つの製品に複数の価格が紐づきます。 - 価格(
price_...
):通貨、金額、課金間隔(毎月/毎年)、トライアル、税設定、ティアなど。サブスクは価格に紐づきます。
Checkout で価格 ID を使う理由
- サブスクには正確な課金条件が必要です。
price_...
に紐づけることで、更新課金、按分、トライアル、Stripe Tax が正しく機能します。 - 更新時の請求書行にも同じ
price_...
が入り、Webhook がプランを特定して各サイクルでクレジットを付与できます。 - 一時的なインライン価格より安全で運用しやすい:金額やルールは Stripe 側で管理し、コードは安定します。
Stripe で価格 ID を見つける手順
- ダッシュボード → 製品 → 対象の製品を選択。
- 価格テーブルの行末「︙」(三点) をクリック → 「価格 ID をコピー」。
price_...
で始まります。prod_...
(製品 ID)と混同しないでください。
環境変数(任意だが推奨)
# プランと Stripe 価格をマッピング。空ならインライン price_data にフォールバック
NEXT_PUBLIC_STRIPE_PRICE_LAUNCH_MONTHLY=price_...
NEXT_PUBLIC_STRIPE_PRICE_SCALE_MONTHLY=price_...
NEXT_PUBLIC_STRIPE_PRICE_LAUNCH_YEARLY=price_...
NEXT_PUBLIC_STRIPE_PRICE_SCALE_YEARLY=price_...
# CNY 価格(任意)
NEXT_PUBLIC_STRIPE_PRICE_LAUNCH_MONTHLY_CNY=price_...
NEXT_PUBLIC_STRIPE_PRICE_SCALE_MONTHLY_CNY=price_...
NEXT_PUBLIC_STRIPE_PRICE_LAUNCH_YEARLY_CNY=price_...
NEXT_PUBLIC_STRIPE_PRICE_SCALE_YEARLY_CNY=price_...
価格 ID の有無による動作
- サブスクプランに Price ID があれば、Checkout はそれを直接使用します。
- 無い場合は、
src/data/pricing.ts
の金額でインラインprice_data
を使ってセッションを作成します(安全なフォールバック)。
更新(リニューアル)とクレジット
本テンプレートは更新時のクレジット自動付与に対応しています:
- Webhook
invoice.payment_succeeded
(billing_reason=subscription_cycle
の場合)で、当該期間の更新注文を作成し、プランのクレジットを付与します。 - 冪等性:同一
(subscription_id, period_start)
の注文が既にあればスキップします。 - 初回購入は引き続き
checkout.session.completed
で処理します。二重付与を避けるため、サイクル外の請求書は無視します。
リマインダー:テスト時は Webhook 転送を設定
ローカル(または本番以外)での検証では、Stripe のイベントを必ずバックエンドに転送してください。そうしないと支払いは成功しても、注文/クレジットが確定しません。
stripe listen --forward-to localhost:3000/api/pay/webhook/stripe
トンネル/リモート URL を利用する場合は、localhost の代わりにそのドメインを指定してください。
その他の決済オプション
Stripe は数ある選択肢のひとつです。暗号資産(クリプト)決済や PayPal など他の手段が必要な場合はご連絡ください。ユースケースと市場に合ったプロバイダの選定・実装をお手伝いします。