Stripe決済入門 - オンライン決済の実装

intermediate | 55分 で読める | 2025.12.18

公式ドキュメント

このチュートリアルで学ぶこと

  • Stripeアカウント設定
  • Checkout Session
  • Webhook処理
  • サブスクリプション
  • テスト方法

Step 1: セットアップ

npm install stripe @stripe/stripe-js
// lib/stripe.ts
import Stripe from 'stripe';

export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
 apiVersion: '2024-12-18.acacia',
});

ポイント: Checkout SessionはStripeがホストする決済ページを生成します。PCI DSS準拠のフォームを自前で実装する必要がなく、最短で安全な決済を実現できます

Step 2: Checkout Session作成

// app/api/checkout/route.ts
import { stripe } from '@/lib/stripe';
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
 const { priceId } = await request.json();

 const session = await stripe.checkout.sessions.create({
 mode: 'payment',
 payment_method_types: ['card'],
 line_items: [
 {
 price: priceId,
 quantity: 1,
 },
 ],
 success_url: `${process.env.NEXT_PUBLIC_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
 cancel_url: `${process.env.NEXT_PUBLIC_URL}/cancel`,
 });

 return NextResponse.json({ url: session.url });
}

Step 3: クライアント側

'use client';
import { loadStripe } from '@stripe/stripe-js';

const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);

export function CheckoutButton({ priceId }: { priceId: string }) {
 const handleClick = async () => {
 const res = await fetch('/api/checkout', {
 method: 'POST',
 body: JSON.stringify({ priceId }),
 });
 const { url } = await res.json();
 window.location.href = url;
 };

 return <button onClick={handleClick}>購入する</button>;
}

注意: WebhookはStripeからの重要な通知です。署名検証(constructEvent)を必ず実装し、不正なリクエストを防いでください。

Step 4: Webhook処理

// app/api/webhook/route.ts
import { stripe } from '@/lib/stripe';
import { headers } from 'next/headers';

export async function POST(request: Request) {
 const body = await request.text();
 const sig = headers().get('stripe-signature')!;

 let event;
 try {
 event = stripe.webhooks.constructEvent(
 body,
 sig,
 process.env.STRIPE_WEBHOOK_SECRET!
 );
 } catch (err) {
 return new Response('Webhook Error', { status: 400 });
 }

 switch (event.type) {
 case 'checkout.session.completed':
 const session = event.data.object;
 // 注文処理
 await handleSuccessfulPayment(session);
 break;
 case 'payment_intent.payment_failed':
 // 失敗処理
 break;
 }

 return new Response('OK');
}

Step 5: サブスクリプション

// サブスクリプション用Checkout
const session = await stripe.checkout.sessions.create({
 mode: 'subscription',
 line_items: [
 {
 price: 'price_xxxxx', // 定期価格ID
 quantity: 1,
 },
 ],
 success_url: `${process.env.NEXT_PUBLIC_URL}/success`,
 cancel_url: `${process.env.NEXT_PUBLIC_URL}/cancel`,
});

// サブスクリプション解約
await stripe.subscriptions.cancel(subscriptionId);

Step 6: Customer Portal

// 顧客ポータルセッション作成
const session = await stripe.billingPortal.sessions.create({
 customer: customerId,
 return_url: `${process.env.NEXT_PUBLIC_URL}/account`,
});

// session.url にリダイレクト

実践メモ: Stripe CLIのlistenコマンドでWebhookをローカルに転送すれば、開発環境でもWebhookのテストが可能です。テストカード4242 4242 4242 4242で成功フローを確認しましょう。

Step 7: テスト

# Stripe CLI インストール
brew install stripe/stripe-cli/stripe

# ログイン
stripe login

# Webhook転送
stripe listen --forward-to localhost:3000/api/webhook

テストカード:

  • 成功: 4242 4242 4242 4242
  • 失敗: 4000 0000 0000 0002
  • 認証必要: 4000 0025 0000 3155

決済実装で最優先すること

Stripe決済では、フロントエンドの表示よりも、サーバー側で金額と商品を確定することが重要です。クライアントから送られた金額をそのまま信用すると、改ざんされた価格で決済される危険があります。

決済完了の判定は、画面遷移だけで行わず、Webhookで確認します。ユーザーが決済後のページを閉じたり、通信が切れたりしても、Webhookを受け取れば注文状態を正しく更新できます。

本番前チェック

  • 金額と通貨をサーバー側で決めているか
  • Webhook署名を検証しているか
  • 二重処理を防ぐためイベントIDを記録しているか
  • テストカードで成功、失敗、キャンセルを確認したか

まとめ

Stripeで安全な決済機能を実装できます。Checkout Sessionで簡単に始め、Webhookで注文処理を自動化しましょう。

参考リソース

← 一覧に戻る
PR
PR
PR
PR