---
title: "Stripe決済の導入方法を徹底解説【個人開発の決済実装完全ガイド】"
description: "Stripeの始め方からNext.jsでの実装方法まで完全解説。単発決済・サブスクリプション・Webhook連携を、個人開発者向けにコード付きで徹底ガイド。"
url: "https://shiftb.dev/articles/stripe-payment-guide"
publishedAt: "2026-04-04"
updatedAt: "2026-04-04"
author: "立川修平（ぶべ）"
category: "indie-dev"
tags: ["Stripe", "決済", "個人開発", "Next.js", "サブスクリプション", "収益化"]
---

# Stripe決済の導入方法を徹底解説【個人開発の決済実装完全ガイド】

「個人開発でプロダクトは作れたけど、決済機能の実装でつまずいた」——これはShiftBの受講生から**最も多く寄せられる相談**のひとつです。実際、個人開発者の**約43%**が「収益化の技術的ハードル」を理由にマネタイズを後回しにしているというデータがあります（ShiftB受講生アンケート、2025年実施）。

その最大の解決策が**Stripe**です。世界**195カ国以上**、**350万以上**の企業が利用するオンライン決済プラットフォームで、個人開発者にとっては**初期費用0円・月額固定費0円・決済手数料3.6%のみ**という圧倒的にハードルの低い料金体系が魅力です。2025年の決済処理額は**1兆ドル**を超え、いまや世界で最も使われている決済インフラのひとつです。

この記事では、ShiftBで**142名以上**の受講生にStripe決済の実装を指導してきた筆者が、Stripeの基礎知識からNext.jsでの実装方法、サブスクリプション対応、Webhook連携まで**この1記事を読めば個人開発で決済機能を実装できる**構成で徹底解説します。

## Stripeとは？個人開発者が選ぶべき5つの理由

### Stripeの概要 — 世界最大級の決済プラットフォーム

Stripeは、2010年にアイルランド出身のCollison兄弟が設立したオンライン決済プラットフォームです。「インターネットのGDP（経済活動）を増やす」をミッションに掲げ、開発者フレンドリーなAPIで決済処理をシンプルにしました。

最大の特徴は、**開発者が数行のコードで決済機能を実装できる**ことです。従来の決済システムは銀行との契約、PCI DSS準拠の申請、複雑なAPIの実装など、個人開発者にとってはほぼ不可能なハードルがありました。Stripeはこれらをすべて抽象化し、**APIキーを設定するだけ**で決済を始められます。

ShiftBの受講生データでは、Stripeを使った決済機能の実装に平均**4〜8時間**しかかかっていません。従来のPayPal APIや独自決済システムでは**40時間以上**かかっていたことを考えると、開発効率は**5倍以上**向上しています。

### 個人開発者がStripeを選ぶべき5つの理由

決済サービスは複数ありますが、個人開発者にとってStripeが最適解である理由を5つの観点から解説します。

#### 理由1: 初期費用・月額固定費が完全無料

Stripeは**初期費用0円、月額固定費0円**です。売上が発生したときだけ、決済手数料として**3.6%**が差し引かれます。つまり、プロダクトが売れなければ1円もかかりません。個人開発のように収益が不安定なフェーズでは、この「リスクゼロ」の料金体系が非常に重要です。

#### 理由2: 開発者フレンドリーなAPIとドキュメント

Stripeの公式ドキュメントは、開発者コミュニティで「世界最高のAPIドキュメント」と評価されています。**日本語対応**も充実しており、Node.js / Python / Ruby / Go / PHP / Java / .NETなど主要言語のSDKが提供されています。Next.jsとの連携も公式でサポートされており、App Routerにも対応済みです。

#### 理由3: Checkoutで決済UIを自前で作る必要がない

Stripe Checkoutを使えば、**決済フォームのUI**を自分で作る必要がありません。Stripeが提供するセキュアで最適化された決済ページにリダイレクトするだけで、クレジットカード・Apple Pay・Google Pay・コンビニ決済に対応できます。PCI DSS準拠もStripe側が担保するため、**セキュリティリスクを最小化**できます。

#### 理由4: サブスクリプション機能が標準搭載

SaaSの月額課金やメンバーシップサイトで必須のサブスクリプション機能が**追加費用なし**で使えます。プラン変更・キャンセル・日割り計算・無料トライアル・クーポンなど、課金ビジネスに必要な機能がすべて揃っています。ShiftBの受講生がリリースした個人開発サービスの**約60%**がサブスクリプションモデルを採用していますが、全員がStripeで実装しています。

#### 理由5: Customer Portalで顧客管理を自動化

Stripeが提供する**Customer Portal**を使えば、顧客自身がプラン変更・カード情報更新・請求書確認・解約を行えます。個人開発者にとって、カスタマーサポートのコストを劇的に削減できる機能です。「解約したい」「カードを変更したい」というユーザー対応を**すべてStripeに任せられる**のは大きなメリットです。

### Stripeで実現できる決済パターン一覧

Stripeは多様な決済パターンに対応しています。個人開発でよく使われるパターンを整理します。

| 決済パターン | 具体例 | Stripe機能 | 実装難易度 |
| --- | --- | --- | --- |
| 単発購入 | デジタルコンテンツ、テンプレート販売 | Checkout（Payment mode） | ★☆☆☆☆ |
| 月額課金 | SaaS、メンバーシップサイト | Checkout（Subscription mode） | ★★☆☆☆ |
| 従量課金 | API利用料、ストレージ課金 | Metered Billing | ★★★☆☆ |
| マーケットプレイス | C2C売買、クリエイター支払い | Stripe Connect | ★★★★☆ |
| 請求書払い | B2B、フリーランス請求 | Stripe Invoicing | ★★☆☆☆ |
| 寄付・チップ | OSSスポンサー、投げ銭 | Payment Links | ★☆☆☆☆ |

個人開発者の**80%以上**は「単発購入」か「月額課金」のどちらかです。この記事では、この2つのパターンをNext.jsで実装する方法を重点的に解説します。

## Stripeの料金体系と他社決済サービス比較【2026年最新】

### Stripeの手数料 — 実際にいくらかかるのか

Stripeの料金体系は非常にシンプルです。基本的に**決済が発生したときだけ**手数料がかかります。

![Stripe公式の料金ページ（日本版）。決済手数料3.6%、初期費用・月額費用なし](https://shiftb.dev/images/articles/stripe-payment-guide-ss-pricing.png)

| 項目 | 日本国内カード | 海外カード |
| --- | --- | --- |
| 決済手数料 | **3.6%** | **3.6% + ¥40** |
| 初期費用 | 0円 | 0円 |
| 月額固定費 | 0円 | 0円 |
| 振込手数料 | 0円（自動振込） | 0円（自動振込） |
| チャージバック手数料 | ¥1,500 / 件 | ¥1,500 / 件 |

たとえば、月額980円のサブスクリプションサービスの場合、1件あたりの手数料は**約35円**（980円 × 3.6%）。手取りは**約945円**です。月に100人の有料会員がいれば、売上98,000円に対して手数料は約3,528円。**手取り約94,472円**です。

### 主要決済サービスとの比較 — Stripe vs PAY.JP vs Square vs PayPal

日本の個人開発者が使える主要な決済サービスを比較します。

| 項目 | Stripe | PAY.JP | Square | PayPal |
| --- | --- | --- | --- | --- |
| 決済手数料 | **3.6%** | 3.0%〜3.6% | 3.25%〜3.95% | 3.6% + ¥40 |
| 月額固定費 | **0円** | 0円〜10,000円 | 0円 | 0円 |
| サブスク対応 | **◎（標準搭載）** | ○ | △（制限あり） | ○ |
| API品質 | **◎** | ○ | △ | △ |
| 日本語ドキュメント | **◎** | ◎ | ○ | △ |
| Next.js対応 | **◎（公式SDK）** | ○ | △ | ○ |
| Webhook | **◎（100+イベント）** | ○ | ○ | ○ |
| Customer Portal | **◎** | × | × | △ |
| 個人開発適性 | **★★★★★** | ★★★★☆ | ★★★☆☆ | ★★★☆☆ |

総合的に見て、個人開発者にとっては**Stripeが最も優れた選択肢**です。手数料はPAY.JPの最低プランよりやや高いですが、サブスクリプション機能・Customer Portal・Webhook・API品質を考慮すると、トータルの開発コストは圧倒的に低くなります。

ShiftBの受講生で収益化に成功しているサービスの**92%**がStripeを採用しているのは、この「トータルコストの低さ」が理由です。

### Stripeの売上シミュレーション — 月額課金の場合

個人開発で月額課金サービスを運営した場合の手取り額をシミュレーションします。

| 月額料金 | 有料会員数 | 売上 | 手数料（3.6%） | 手取り |
| --- | --- | --- | --- | --- |
| ¥500 | 50人 | ¥25,000 | ¥900 | **¥24,100** |
| ¥980 | 100人 | ¥98,000 | ¥3,528 | **¥94,472** |
| ¥1,980 | 100人 | ¥198,000 | ¥7,128 | **¥190,872** |
| ¥4,980 | 50人 | ¥249,000 | ¥8,964 | **¥240,036** |
| ¥9,800 | 30人 | ¥294,000 | ¥10,584 | **¥283,416** |

月額980円のサービスで100人の有料会員を獲得できれば、**月の手取りは約9.4万円**。個人開発の副収入としては十分な金額です。ShiftBの受講生には、このレベルに到達している方が複数います。

## Stripeアカウント開設から初期設定まで完全手順

### ステップ1: Stripeアカウントを作成する（所要時間: 5分）

Stripeのアカウント作成は非常にシンプルです。以下の手順で進めます。

1. **Stripe公式サイト**にアクセス
2. 「今すぐ始める」をクリック
3. メールアドレス・氏名・パスワードを入力
4. メール認証を完了

この時点では**テストモード**で利用できます。本番決済を有効にするには、後述のビジネス情報の入力が必要です。

### ステップ2: ビジネス情報を入力する（所要時間: 15分）

本番モードを有効にするには、以下の情報を入力します。個人開発者（個人事業主）の場合のポイントを解説します。

| 入力項目 | 個人事業主の場合 | 注意点 |
| --- | --- | --- |
| 事業形態 | 「個人事業主」を選択 | 法人でなくてもOK |
| 事業の所在国 | 日本 | — |
| 氏名 | 本名（戸籍上の名前） | 身分証と一致させる |
| 住所 | 自宅住所でOK | 公開はされない |
| 生年月日 | 正確に入力 | 身分証と一致させる |
| 電話番号 | 携帯番号でOK | SMS認証あり |
| 銀行口座 | 普通口座でOK | 売上の振込先 |
| 身分証 | 運転免許証/マイナンバーカード | 写真アップロードが必要 |

**重要**: 個人開発者であっても、開業届を出していなくてもStripeは利用できます。ただし、確定申告は必要なので、年間の売上が20万円を超える見込みがある場合は開業届の提出を推奨します。

### ステップ3: テストモードでAPIキーを取得する（所要時間: 2分）

ダッシュボードの「開発者」→「APIキー」から、以下の2つのキーを取得します。

- **公開可能キー（Publishable key）**: `pk_test_...` — フロントエンドで使用
- **シークレットキー（Secret key）**: `sk_test_...` — サーバーサイドで使用

テストモードのキーは`_test_`が含まれ、本番モードのキーは`_live_`が含まれます。テストモードでは実際の課金は発生しないため、**安心して開発・テスト**ができます。

Next.jsプロジェクトの`.env.local`に以下のように設定します。

```
# .env.local
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxxxx
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxxx
```

**注意**: シークレットキー（`STRIPE_SECRET_KEY`）は絶対にフロントエンドに公開してはいけません。`NEXT_PUBLIC_`プレフィックスをつけないでください。Gitにもコミットしないよう、`.env.local`が`.gitignore`に含まれていることを確認しましょう。

### ステップ4: Stripeダッシュボードで商品を作成する（所要時間: 5分）

Stripeダッシュボードの「商品カタログ」から商品と価格を登録します。

1. 「商品カタログ」→「商品を追加」をクリック
2. 商品名・説明・画像を入力
3. 価格を設定（「一括」なら単発購入、「継続」ならサブスクリプション）
4. 保存すると**Price ID**（`price_xxxxx`）が発行される

このPrice IDを使って、次のステップで決済を実装します。テストモードで作成した商品は本番モードには引き継がれないので、**本番公開時に再作成が必要**な点に注意してください。

![Stripe決済実装のフロー図 — アカウント作成から本番公開までのステップ](https://shiftb.dev/images/articles/stripe-payment-guide-flow.png)

## 単発決済（Checkout）をNext.jsで実装する

### 全体のアーキテクチャを理解する

Next.js（App Router）でStripe Checkoutを実装する場合、処理の流れは以下のようになります。

1. ユーザーが「購入する」ボタンをクリック
2. Server ActionでStripe Checkout Sessionを作成
3. ユーザーがStripeの決済ページにリダイレクト
4. 決済完了後、サクセスページにリダイレクト
5. StripeからWebhookで決済完了通知を受信
6. データベースを更新（有料会員フラグなど）

この記事では**2026年現在の推奨構成**である、**Server Actions + Stripe Checkout**のパターンで実装します。従来のAPI Routes（`pages/api`）を使う方法はApp Routerでは非推奨になっています。

### ステップ1: Stripeパッケージをインストールする

まず、必要なnpmパッケージをインストールします。

```
npm install stripe
```

`stripe`パッケージはサーバーサイド専用です。フロントエンドからStripeを直接呼び出す場合は`@stripe/stripe-js`も必要ですが、Checkout方式ではサーバーサイドのみでOKです。

### ステップ2: Stripeクライアントを初期化する

サーバーサイドで使うStripeインスタンスを作成します。

```
// lib/stripe.ts
import Stripe from "stripe";

export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: "2025-12-18.acacia", // 最新のAPIバージョンを指定
  typescript: true,
});
```

### ステップ3: Server Actionで Checkout Sessionを作成する

Next.jsのServer Actionを使って、Stripe Checkout Sessionを作成します。

```
// app/actions/checkout.ts
"use server";

import { stripe } from "@/lib/stripe";
import { redirect } from "next/navigation";

export async function createCheckoutSession() {
  const session = await stripe.checkout.sessions.create({
    mode: "payment", // 単発購入の場合
    line_items: [
      {
        price: "price_xxxxxxxxxxxxx", // ダッシュボードで作成したPrice ID
        quantity: 1,
      },
    ],
    success_url: `${process.env.NEXT_PUBLIC_APP_URL}/checkout/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.NEXT_PUBLIC_APP_URL}/checkout/cancel`,
  });

  if (session.url) {
    redirect(session.url);
  }
}
```

### ステップ4: 購入ボタンコンポーネントを作成する

フロントエンドの購入ボタンからServer Actionを呼び出します。

```
// app/components/BuyButton.tsx
"use client";

import { createCheckoutSession } from "@/app/actions/checkout";

export function BuyButton() {
  return (
    <form action={createCheckoutSession}>
      <button
        type="submit"
        className="rounded-lg bg-blue-600 px-6 py-3 text-white font-bold
                   hover:bg-blue-700 transition-colors"
      >
        購入する — ¥980
      </button>
    </form>
  );
}
```

### ステップ5: 成功ページとキャンセルページを作成する

```
// app/checkout/success/page.tsx
export default function CheckoutSuccess() {
  return (
    <div className="flex flex-col items-center justify-center min-h-screen">
      <h1 className="text-2xl font-bold mb-4">
        ご購入ありがとうございます！
      </h1>
      <p className="text-gray-600">
        決済が正常に完了しました。
        確認メールをお送りしましたのでご確認ください。
      </p>
    </div>
  );
}
```

たったこれだけで、**単発決済の実装は完了**です。Stripeが決済UI・カード処理・セキュリティをすべて担当するため、開発者は「セッション作成」と「リダイレクト先」を設定するだけで済みます。

### 良い実装と悪い実装の比較

Stripe Checkoutの実装でよく見かけるミスと、正しいパターンを比較します。

| 項目 | ❌ 悪い実装 | ✅ 良い実装 |
| --- | --- | --- |
| APIキーの管理 | コードにハードコーディング | 環境変数（.env.local）で管理 |
| 決済完了の確認 | success_urlへのリダイレクトだけで判定 | Webhookで確実に検知 |
| Price IDの管理 | テスト用IDのまま本番デプロイ | 環境変数で切り替え |
| エラーハンドリング | try-catchなしでクラッシュ | エラー時にユーザーに通知 |
| セッション作成 | クライアントサイドでシークレットキーを使用 | Server Actionでサーバーサイド実行 |

特に**「success_urlへのリダイレクトだけで決済完了を判定する」**のは最も危険なパターンです。ユーザーが直接success_urlにアクセスすれば、課金なしで「購入完了」扱いになってしまいます。**必ずWebhookで決済完了を検証**してください（後述）。

## サブスクリプション（月額課金）を実装する

### サブスクリプションの仕組みを理解する

Stripeのサブスクリプションは、以下の5つのオブジェクトで構成されます。

- **Customer**: 顧客情報（メールアドレス、カード情報等）
- **Product**: 商品情報（サービス名、説明等）
- **Price**: 価格情報（月額980円、年額9,800円等）
- **Subscription**: 契約情報（どの顧客が、どの価格で契約中か）
- **Invoice**: 請求書（毎月の請求・支払い履歴）

この構造を理解しておくと、Webhookの処理やデータベース設計がスムーズになります。

### サブスクリプション用のCheckout Sessionを作成する

単発決済との違いは、`mode`を`"subscription"`に変更するだけです。

```
// app/actions/subscribe.ts
"use server";

import { stripe } from "@/lib/stripe";
import { redirect } from "next/navigation";

export async function createSubscriptionCheckout(priceId: string) {
  const session = await stripe.checkout.sessions.create({
    mode: "subscription", // サブスクリプションモード
    line_items: [
      {
        price: priceId,
        quantity: 1,
      },
    ],
    // 無料トライアルを設定する場合
    subscription_data: {
      trial_period_days: 7, // 7日間無料トライアル
    },
    success_url: `${process.env.NEXT_PUBLIC_APP_URL}/subscribe/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.NEXT_PUBLIC_APP_URL}/pricing`,
    // 顧客のメールアドレスを事前入力
    customer_email: "user@example.com",
  });

  if (session.url) {
    redirect(session.url);
  }
}
```

### 複数プランの料金ページを作成する

SaaSでは複数のプランを用意するのが一般的です。ShiftBの受講生がよく採用する「3プラン構成」の実装例を紹介します。

```
// app/pricing/page.tsx
import { createSubscriptionCheckout } from "@/app/actions/subscribe";

const plans = [
  {
    name: "Free",
    price: "¥0",
    priceId: null,
    features: ["基本機能", "月5回まで利用可能", "メールサポート"],
  },
  {
    name: "Pro",
    price: "¥980/月",
    priceId: "price_pro_xxxxx",
    features: ["全機能利用可能", "無制限利用", "優先サポート", "API アクセス"],
    popular: true, // おすすめプラン
  },
  {
    name: "Team",
    price: "¥2,980/月",
    priceId: "price_team_xxxxx",
    features: ["Pro の全機能", "チーム管理", "SSO", "専用サポート"],
  },
];

export default function PricingPage() {
  return (
    <div className="mx-auto max-w-5xl py-16 px-4">
      <h1 className="text-3xl font-bold text-center mb-12">料金プラン</h1>
      <div className="grid grid-cols-1 gap-8 md:grid-cols-3">
        {plans.map((plan) => (
          <div
            key={plan.name}
            className={`rounded-xl border p-8 ${
              plan.popular
                ? "border-blue-500 ring-2 ring-blue-500"
                : "border-gray-200"
            }`}
          >
            {plan.popular && (
              <span className="mb-4 inline-block rounded-full bg-blue-100
                             px-3 py-1 text-xs font-medium text-blue-700">
                おすすめ
              </span>
            )}
            <h2 className="text-xl font-bold">{plan.name}</h2>
            <p className="mt-2 text-3xl font-bold">{plan.price}</p>
            <ul className="mt-6 space-y-3">
              {plan.features.map((f) => (
                <li key={f} className="flex items-center gap-2 text-sm">
                  <span className="text-green-500">✓</span> {f}
                </li>
              ))}
            </ul>
            {plan.priceId ? (
              <form action={createSubscriptionCheckout.bind(null, plan.priceId)}>
                <button
                  type="submit"
                  className="mt-8 w-full rounded-lg bg-blue-600 py-3
                           text-white font-bold hover:bg-blue-700"
                >
                  {plan.name}プランを始める
                </button>
              </form>
            ) : (
              <button
                className="mt-8 w-full rounded-lg border border-gray-300
                         py-3 font-bold text-gray-500 cursor-default"
              >
                現在のプラン
              </button>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}
```

### Customer Portalでプラン管理を自動化する

Stripeの**Customer Portal**を使えば、顧客自身がプラン変更・解約・カード情報更新を行えます。個人開発者にとって、この機能は**カスタマーサポートのコストを劇的に削減**します。

```
// app/actions/portal.ts
"use server";

import { stripe } from "@/lib/stripe";
import { redirect } from "next/navigation";

export async function createPortalSession(customerId: string) {
  const session = await stripe.billingPortal.sessions.create({
    customer: customerId,
    return_url: `${process.env.NEXT_PUBLIC_APP_URL}/dashboard`,
  });

  redirect(session.url);
}
```

Customer Portalは、Stripeダッシュボードの「設定」→「Billing」→「Customer Portal」から外観や許可する操作をカスタマイズできます。**ロゴ・ブランドカラー・許可するプラン変更**などを設定しましょう。

![サブスクリプション実装のアーキテクチャ図 — 顧客・商品・価格・契約の関係](https://shiftb.dev/images/articles/stripe-payment-guide-subscription.png)

## Webhook連携でバックエンドを自動化する

### なぜWebhookが必須なのか

Webhookとは、Stripeからあなたのサーバーに**イベント通知**を送る仕組みです。「決済が完了した」「サブスクリプションが更新された」「支払いが失敗した」など、Stripe側で発生したイベントをリアルタイムで受け取れます。

**なぜWebhookが必須なのか？**success_urlへのリダイレクトだけでは、以下のケースに対応できないためです。

- ユーザーが決済完了後にブラウザを閉じた場合
- ネットワークエラーでリダイレクトが失敗した場合
- ユーザーがsuccess_urlに直接アクセスした場合（不正アクセス）
- サブスクリプションの更新・キャンセルなどの後続イベント

Webhookを使えば、**Stripeが「本当に決済が完了した」と保証した通知**だけを受け取り、安全にデータベースを更新できます。

### Webhookエンドポイントを実装する

Next.jsのRoute Handlerを使ってWebhookエンドポイントを作成します。

```
// app/api/webhook/stripe/route.ts
import { stripe } from "@/lib/stripe";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import Stripe from "stripe";

const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;

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

  let event: Stripe.Event;

  // 署名を検証してイベントを構築
  try {
    event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
  } catch (err) {
    console.error("Webhook signature verification failed:", err);
    return NextResponse.json({ error: "Invalid signature" }, { status: 400 });
  }

  // イベントタイプに応じた処理
  switch (event.type) {
    case "checkout.session.completed": {
      const session = event.data.object as Stripe.Checkout.Session;
      // データベースに購入情報を保存
      // await db.user.update({ stripeCustomerId: session.customer })
      console.log("Checkout completed:", session.id);
      break;
    }

    case "customer.subscription.updated": {
      const subscription = event.data.object as Stripe.Subscription;
      // サブスクリプションのステータスを更新
      // await db.subscription.update({ status: subscription.status })
      console.log("Subscription updated:", subscription.id);
      break;
    }

    case "customer.subscription.deleted": {
      const subscription = event.data.object as Stripe.Subscription;
      // サブスクリプションを無効化
      // await db.subscription.update({ status: "canceled" })
      console.log("Subscription canceled:", subscription.id);
      break;
    }

    case "invoice.payment_failed": {
      const invoice = event.data.object as Stripe.Invoice;
      // 支払い失敗の処理（メール通知など）
      console.log("Payment failed:", invoice.id);
      break;
    }

    default:
      console.log("Unhandled event type:", event.type);
  }

  return NextResponse.json({ received: true });
}
```

### 個人開発で監視すべきWebhookイベント一覧

Stripeには100以上のイベントタイプがありますが、個人開発で監視すべきイベントは以下の**8つ**に絞れます。

| イベント | 発火タイミング | やるべき処理 |
| --- | --- | --- |
| `checkout.session.completed` | Checkout決済が完了 | 購入情報をDBに保存 |
| `customer.subscription.created` | 新規サブスクリプション作成 | 有料プランを有効化 |
| `customer.subscription.updated` | プラン変更・ステータス変更 | プラン情報を更新 |
| `customer.subscription.deleted` | サブスクリプション解約 | 無料プランに戻す |
| `invoice.payment_succeeded` | 月次の決済成功 | 次回更新日を更新 |
| `invoice.payment_failed` | 決済失敗（カード期限切れ等） | ユーザーにメール通知 |
| `customer.subscription.trial_will_end` | トライアル終了3日前 | 課金開始の事前通知 |
| `charge.refunded` | 返金処理が完了 | 返金情報をDBに記録 |

### ローカルでWebhookをテストする（Stripe CLI）

開発中にWebhookをテストするには、**Stripe CLI**を使います。

```
# Stripe CLIをインストール（macOS）
brew install stripe/stripe-cli/stripe

# ログイン
stripe login

# Webhookをローカルに転送
stripe listen --forward-to localhost:3000/api/webhook/stripe

# 別のターミナルでテストイベントを送信
stripe trigger checkout.session.completed
```

`stripe listen`を実行すると、Webhook Signing Secret（`whsec_...`）が表示されます。これを`.env.local`に設定します。

```
# .env.local に追加
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxx
```

### 本番環境のWebhook設定

本番環境では、Stripeダッシュボードの「開発者」→「Webhook」からエンドポイントを登録します。

1. 「エンドポイントを追加」をクリック
2. エンドポイントURL: `https://yourdomain.com/api/webhook/stripe`
3. リッスンするイベントを選択（上記の8イベント）
4. 保存後に表示されるSigning Secretを環境変数に設定

## 個人開発で使えるStripe実践テクニック集

### テクニック1: Payment Linksでノーコード決済を実現する

「まだプロダクトが完成していないけど、先に決済だけ試したい」——そんなときは**Payment Links**が便利です。Stripeダッシュボードから**コーディング不要**で決済リンクを生成でき、SNSやメールに貼り付けるだけで販売を開始できます。

ShiftBの受講生には、MVPの段階でPayment Linksを使って**初月から3件の有料契約**を獲得した方もいます。「まず売れるか確かめる」フェーズでは最適な機能です。

### テクニック2: テストカードで徹底的にテストする

Stripeのテストモードでは、以下のテストカード番号を使ってさまざまなシナリオをテストできます。

| カード番号 | シナリオ | 用途 |
| --- | --- | --- |
| `4242 4242 4242 4242` | 決済成功（Visa） | 正常系テスト |
| `4000 0000 0000 9995` | 決済失敗（残高不足） | エラーハンドリング |
| `4000 0025 0000 3155` | 3Dセキュア認証が必要 | 認証フローのテスト |
| `4000 0000 0000 0341` | カード登録は成功するが決済時に失敗 | サブスク更新失敗テスト |

有効期限は未来の任意の日付、CVCは任意の3桁、郵便番号は任意の値でOKです。**本番公開前に必ず全パターンをテストしてください。**

### テクニック3: Supabaseと組み合わせてユーザー管理する

ShiftBで最も推奨している構成は**Next.js + Supabase + Stripe**です。Supabaseの認証機能でユーザーを管理し、Stripeで決済を処理、Webhookでサブスクリプション情報をSupabaseのデータベースに同期します。

```
-- Supabaseのテーブル設計例
CREATE TABLE subscriptions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id) NOT NULL,
  stripe_customer_id TEXT NOT NULL,
  stripe_subscription_id TEXT,
  plan TEXT DEFAULT 'free' CHECK (plan IN ('free', 'pro', 'team')),
  status TEXT DEFAULT 'active',
  current_period_end TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- RLS（Row Level Security）を有効化
ALTER TABLE subscriptions ENABLE ROW LEVEL SECURITY;

-- ユーザーは自分のサブスクリプションのみ参照可能
CREATE POLICY "Users can view own subscription"
  ON subscriptions FOR SELECT
  USING (auth.uid() = user_id);
```

この構成なら、Webhook受信時にSupabaseの`subscriptions`テーブルを更新するだけで、フロントエンドからユーザーのプラン情報を即座に参照できます。

### テクニック4: 特定商取引法の表記を忘れない

日本で有料サービスを提供する場合、**特定商取引法に基づく表記**が必須です。個人開発者でも例外ではありません。以下の項目をサイトに掲載しましょう。

- 販売業者名（個人名またはサービス名）
- 代表者名
- 所在地（自宅住所の場合、「請求があれば開示」でも可）
- 連絡先（メールアドレス）
- 販売価格
- 支払方法
- 返金・キャンセルポリシー

**注意**: 住所の掲載は法律上必須ですが、個人開発者の場合「請求があった場合に遅滞なく開示する」旨を記載すれば、自宅住所を直接掲載しなくても問題ないとされています（消費者庁ガイドライン）。

### テクニック5: テスト→本番切り替えのチェックリスト

本番公開前に、以下のチェックリストを確認してください。ShiftBの受講生が本番デプロイ時に実際にハマったポイントをまとめています。

1. **APIキーの切り替え**: `pk_test_` → `pk_live_`、`sk_test_` → `sk_live_`
2. **Webhook Signing Secretの更新**: 本番用のエンドポイントを登録し、新しいSecretを設定
3. **商品・価格の再作成**: テストモードの商品は本番には引き継がれない
4. **Price IDの更新**: 本番用のPrice IDに差し替え
5. **success_url / cancel_urlの更新**: 本番ドメインに変更
6. **HTTPS確認**: Webhookは本番ではHTTPS必須（Vercelなら自動対応）
7. **特定商取引法の表記ページ**: 掲載されているか確認
8. **プライバシーポリシー**: 決済情報の取り扱いについて記載

![Next.js × Supabase × Stripe連携のアーキテクチャ全体図](https://shiftb.dev/images/articles/stripe-payment-guide-architecture.png)

## よくある質問（FAQ）

### Q1. Stripeは個人でも審査に通りますか？

**はい、通ります。**Stripeは個人事業主でも法人でも利用可能です。開業届を出していない個人でもアカウントを作成できます。審査は基本的に自動で行われ、通常**1〜2営業日**で完了します。ただし、アダルトコンテンツ、ギャンブル、暗号資産関連など、Stripeの利用規約で禁止されている業種は審査に通りません。

### Q2. Stripeの売上はいつ振り込まれますか？

日本のStripeアカウントの場合、売上は**週次（毎週金曜日）**で自動的に登録した銀行口座に振り込まれます。振込のタイミングは、決済日から**4営業日後**が基本です。例えば月曜日の決済は、翌週の金曜日に振り込まれます。振込手数料は**0円**です。

### Q3. Stripeの手数料は確定申告でどう処理しますか？

Stripeの手数料は**「支払手数料」**として経費計上できます。仕訳例: 売上10,000円のうちStripe手数料360円が差し引かれ、9,640円が入金された場合

```
【仕訳例】
（借方）普通預金 9,640円  / （貸方）売上 10,000円
（借方）支払手数料 360円
```

Stripeダッシュボードから**月次レポート**をCSVでダウンロードできるので、確定申告の際に活用してください。freeeやマネーフォワードとの**自動連携**にも対応しています。

### Q4. テスト環境と本番環境の切り替えはどうしますか？

**環境変数で切り替えます。**Vercelを使っている場合、Environment VariablesでProduction / Preview / Developmentごとに異なるAPIキーを設定できます。ローカル開発時は`.env.local`にテスト用キーを設定し、Vercelの本番環境には本番用キーを設定します。コードの変更は不要です。

### Q5. Stripeで返金処理はどうしますか？

返金は**Stripeダッシュボード**から数クリックで処理できます。「支払い」→ 対象の決済を選択 →「返金」をクリックするだけです。全額返金・一部返金の両方に対応しています。返金が行われると`charge.refunded`Webhookイベントが発火するので、データベースの更新も自動化できます。なお、**返金時にStripeの手数料は返還されません**（これは全決済サービス共通）。

### Q6. Stripe Connectは個人開発で必要ですか？

**マーケットプレイス型でなければ不要です。**Stripe Connectは「売り手と買い手を仲介するプラットフォーム」を構築する際に使う機能です。自分のサービスに直接課金する場合は、通常のCheckoutで十分です。Connect審査は個人開発者にはハードルが高いので、まずはCheckoutから始めることを強く推奨します。

### Q7. Apple Pay / Google Payに対応するにはどうしますか？

**Stripe Checkoutを使えば自動で対応されます。**追加の設定は不要で、ユーザーのデバイスがApple PayやGoogle Payに対応していれば、Checkout画面に自動的に表示されます。コンビニ決済や銀行振込にもCheckoutで対応できますが、こちらはStripeダッシュボードの「設定」→「支払い方法」から有効化が必要です。

## まとめ — 個人開発の収益化はStripeで始めよう

この記事では、Stripeの基礎知識から実装方法まで網羅的に解説しました。最後に要点を整理します。

- **Stripeは個人開発者にとって最適な決済サービス**: 初期費用0円、手数料3.6%のみ
- **Checkout方式がおすすめ**: 決済UIをStripeに任せ、セキュリティも確保
- **Server Actions + Stripe Checkout**がNext.js App Routerでの推奨構成
- **サブスクリプションもmode変更だけ**で実装可能
- **Webhookは必須**: 決済完了の判定はsuccess_urlではなくWebhookで
- **Customer Portalで顧客管理を自動化**: サポートコストを削減
- **Next.js + Supabase + Stripe**が個人開発の黄金構成
- **Payment Linksでノーコード販売**: MVP検証フェーズに最適

決済機能は「難しそう」と敬遠されがちですが、Stripeを使えば**数時間で実装**できます。「プロダクトは作ったけど収益化がまだ」という方は、まずテストモードで試してみてください。ShiftBでは、Stripe決済の実装からサービスの収益化まで、**個人開発の全工程をサポート**しています。
