3. Stripe決済

NextJS

Stripeアカウントの作成とAPIキーの取得

Stripeの公式サイト でアカウントを作成し、
「開発者」 → 「APIキー」 から 公開可能キー(pk_) と 秘密キー(sk_) を取得します

.env.local

STRIPE_PUBLIC_KEY=pk_test_XXXXXXXXXXXXXXXXXXXXXXXX
STRIPE_SECRET_KEY=sk_test_XXXXXXXXXXXXXXXXXXXXXXXX
NEXT_PUBLIC_STRIPE_PUBLIC_KEY=pk_test_XXXXXXXXXXXXXXXXXXXXXXXX

APIキーを記述します(NEXT_PUBLIC_STRIPE_PUBLIC_KEY はクライアント側で使うため NEXT_PUBLIC_ を付けています?)

ライブラリのインストール

npm install stripe @stripe/stripe-js   <--- stripeはサーバー側(API)で使います
                                       <--- @stripe/stripe-jsはクライアント側(決済ページ)で使います

pages/api/checkout.ts

import { NextApiRequest, NextApiResponse } from "next";
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {  <--- .env.localの値を参照
    apiVersion: "2023-10-16",   <--- 使用するStripe APIのバージョンを指定します
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) { <--- apiのreqとres
    if (req.method !== "POST") {
        return res.status(405).json({ error: "Method not allowed"});
    }

    try {
        const { items } = req.body;
        const session = await stripe.checkout.sessions.create({ <--- stripeのcheckoutセッションを作成
            payment_method_types: ["card"], <--- 決済方法はカード決済のみ
            line_items: items.map((item: any) => ({  <--- 商品情報
                price_data: {
                    currency: "jpy",
                    product_data: { name: item.name },
                    unit_amount: item.price * 100,  <--- 商品の単価を整数で指定(日本円は100倍します)
                },
                quantity: item.quantity,
            })),
            mode: "payment",  <--- 支払いモード(Not受け取りモード)
            succes_url: `${req.headers.origin}/success?session_id={CHECKOUT_SESSION_ID}`,
            cancel_url: `${req.headers.origin}/cancel`,   <--- 支払いが成功・失敗したときのリダイレクトURL
        });

        res.json({ id: session.id });
    } catch (error) {
        res.status(500).json({ error: "failed to create checkout session"});
    }
}

stripeとnext.jsをつなぐAPIをつくります

components/CheckoutButton.tsx

import { loadStripe } from "@stripe/stripe-js";

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

export default function CheckoutButton({ items }: { items: any[] }) {
    const handleCheckout = async() => {
        const res = await fetch("/api/checkout", { <--- pages/api/checkout.tsに商品情報を渡します
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ items }),
        });
        const { id } = await res.json();
        const stripe = await stripePromise;
        stripe?.redirectToCheckout({ sessionId: id });
    };
    return <button onClick={handleCheckout}>購入する</button>
}

カートの商品をStripe Checkoutに送信するボタンです

pages/success.tsx

import { useRouter } from "next/router";

export default function Success() {
    const router = useRouter();
    const sessionId = router.query.session_id;

    return (
        <div>
            <h1>決済完了</h1>
            <p>注文ID: {sessionId}</p>
            <button onClick={() => router.push('/')}>ホームに戻る</button>
        </div>
    );
}

決済完了ページです

流れ

pages/index.tsxで商品リストを作成します→カートに商品を追加→CheckoutButtonを使って購入→Stripeの決済画面に遷移→決済完了後pages/success.tsxにリダイレクト

BACK