Lovableで作ったアプリに『決済』をつける完全ガイド|月額課金・買い切り両対応
『Lovable 決済つける』『Lovable サブスク』で検索した人向け。Stripeを使って、Lovableアプリにお金が入ってくる仕組みを最短で組み込む手順を、画面付きで非エンジニア向けに解説。
1. この記事のゴール#
読み終わったとき、あなたのLovableアプリに『お申し込みボタン → クレジットカード入力 → 月額課金開始 → 有料プラン機能を解放』という一連の流れが組み込まれている状態になります。買い切り(1回払い)も、サブスク(月額/年額)も、同じ仕組みで作れます。
2. 全体の流れ(5分で理解)#
決済というと難しそうですが、登場人物は3つだけです。
- 🛒 あなたのLovableアプリ(『Proにする』ボタンがある画面)
- 💳 Stripe(カード情報を安全に預かってくれる外部サービス)
- 📬 Webhook(『お金が入ったよ』とStripeからアプリに届く通知)
① ユーザーが『Proにする』をクリック
↓
② Lovable がサーバーで Stripe に「決済ページ作って」と依頼
↓
③ ユーザーが Stripe のページでカード入力 → 支払い完了
↓
④ Stripe が Lovable に Webhook で「払われたよ」と通知
↓
⑤ Lovable が DB の『このユーザーは Pro』というフラグを立てる
↓
⑥ ユーザーがアプリに戻ると、Pro機能が解放されている 🎉3. 始める前に用意するもの#
- Stripeアカウント(無料、5分で作れる)
- Lovableで動いているアプリ(このガイドではログイン機能まで作ってある前提)
- 売る商品の名前と価格(例:Proプラン / 月額¥1,980)
4. Stripe側の設定(10分)#
4-1. 商品(Product)と価格(Price)を作る
- Stripeダッシュボード左メニュー → 『商品カタログ』
- 右上『+ 商品を追加』
- 名前:『Proプラン』、説明:『すべての機能が使えます』
- 料金タイプ:『継続』(サブスク) or 『1回限り』(買い切り)
- 価格:1980円 / 月(JPY)
- 保存後に表示される price_xxxxxxxx という ID をメモしておく(後で使う)
4-2. APIキーを取得する
- Stripeダッシュボード右上『開発者』→ 『APIキー』
- 『シークレットキー』を表示してコピー(sk_test_ で始まる文字列)
- 本番運用前は必ず『テストモード』で作業すること
5. Lovable側の設定#
5-1. シークレットを登録
Lovableチャットで以下のように頼みます:
Stripeを使って課金機能をつけたいので、シークレットを2つ登録して:
- STRIPE_SECRET_KEY(後で値を入れます)
- STRIPE_WEBHOOK_SECRET(後で値を入れます)シークレット入力欄が出てきたら、4-2でコピーした sk_test_... を貼り付け。Webhookシークレットは次のステップで取得します。
5-2. 決済ボタンと Webhook を実装する
次のプロンプトをそのままLovableチャットに貼ってください。
Stripe Checkoutで月額課金機能をつけて。仕様:
1. /pricing ページに『Proにアップグレード(¥1,980/月)』ボタン
2. ボタンを押すと createCheckoutSession サーバーファンクションが呼ばれ、
Stripe Checkout のURLにリダイレクト
- 商品の price_id は "price_xxxxxxxx"(4-1でメモしたID)
- mode: "subscription"
- success_url: "/billing/success", cancel_url: "/pricing"
3. /api/public/stripe-webhook を作り、checkout.session.completed と
customer.subscription.updated / deleted を受信
- 必ず stripe.webhooks.constructEvent で署名検証
- DBの users テーブルに plan ('free'|'pro') と stripe_customer_id を保存
4. ヘッダーに現在のプラン表示。Proユーザーだけが /app/pro にアクセスできるよう
ガードをかける6. Webhook の URL を Stripe に登録#
実装が終わったら、Stripeに『支払いがあったらここに通知してね』というURLを教えます。
- プロジェクトの公開URLを確認(例: https://project--xxxx.lovable.app)
- Webhookの完全なURL: https://project--xxxx.lovable.app/api/public/stripe-webhook
- Stripeダッシュボード → 開発者 → Webhooks → 『エンドポイントを追加』
- URLを貼り付け、イベント: checkout.session.completed / customer.subscription.updated / customer.subscription.deleted を選択
- 保存後に表示される『署名シークレット(whsec_...)』をコピー
- Lovableのシークレット STRIPE_WEBHOOK_SECRET にその値を保存
7. 動作確認(テストモード)#
Stripeのテストカード番号で実際のお金を使わずに通しで動かせます。
- ✅ 成功カード:4242 4242 4242 4242(有効期限は未来、CVCは任意の3桁)
- ❌ 失敗カード:4000 0000 0000 0002(残高不足エラーをテスト)
- 🔐 3Dセキュア要求:4000 0027 6000 3184
- /pricing で『アップグレード』をクリック
- Stripe Checkoutで 4242... を入力して支払い
- /billing/success に戻ってきたらフロント側はOK
- Stripeダッシュボード → Webhooks でイベント送信が ✅ 200 になっているか確認
- DBの users テーブルで自分の plan が 'pro' になっているか確認
- /app/pro にアクセスしてガードを通過できるか確認
8. 裏で動いている重要コード(読み飛ばしてOK)#
Webhookの署名検証だけは、もし手動で確認するなら以下のような姿になっています。
// src/routes/api/public/stripe-webhook.ts (抜粋)
const sig = request.headers.get("stripe-signature")!;
const rawBody = await request.text();
const event = stripe.webhooks.constructEvent(
rawBody,
sig,
process.env.STRIPE_WEBHOOK_SECRET!,
);
if (event.type === "checkout.session.completed") {
const session = event.data.object as Stripe.Checkout.Session;
await db.user.update({
where: { id: session.client_reference_id! },
data: { plan: "pro", stripeCustomerId: session.customer as string },
});
}9. よくあるつまずきと解決策#
10. 次の一歩#
- 解約フロー:Stripe Customer Portalを呼び出すボタンを置くだけで、解約・カード変更・領収書ダウンロードが全部Stripe側でできる
- プラン複数化:price_idを複数用意して /pricing にカード3枚(Free/Pro/Team)
- 領収書PDF:Stripe側で自動発行。日本のインボイス制度対応も設定で可能
- 売上通知:『新規Pro契約』を Slack に通知(Slackコネクタ記事参照)
11. 領収書PDF・インボイス制度(適格請求書)対応#
日本でBtoB/BtoC問わず有料サービスを売るなら、購入者から『領収書ください』『インボイス番号入りの請求書ください』と必ず言われます。Stripeはこれを“ほぼ自動”で出せる仕組みを持っているので、自前でPDF生成のコードを書く必要はありません。設定する場所と順番だけ押さえておきましょう。
11-1. Stripeが自動発行してくれるもの・くれないもの
- ✅ 自動:決済成功時のメール領収書(Receipt)— 顧客のメールアドレスに自動送信
- ✅ 自動:Customer Portalからの領収書PDF再ダウンロード(過去全件)
- ✅ 自動:サブスク更新ごとの請求書(Invoice)PDF
- ⚠️ 設定必要:適格請求書発行事業者の登録番号(T+13桁)の表示
- ⚠️ 設定必要:税区分(10% / 8% / 非課税)の明示
- ⚠️ 設定必要:発行者の氏名・住所・登録番号などの“請求書テンプレート”
11-2. ステップA:領収書メールを“ON”にする(最初の3クリック)
- Stripeダッシュボード → 設定 → 『顧客のメール』を開く
- 『支払いが成功したときに領収書を送信』にチェック
- 送信元メールアドレスとブランド名(ロゴ)を設定して保存
11-3. ステップB:インボイス番号(登録番号)を全請求書に印字する
適格請求書発行事業者の登録番号(T+13桁)は、Stripeの“請求書テンプレート”に入れると、以後発行されるすべての請求書PDFに自動で載ります。
- Stripeダッシュボード → 設定 → 『請求書テンプレート(Invoice template)』
- 『発行者の住所と詳細』に、会社名/住所/電話に加えて『登録番号:T1234567890123』を1行追加
- 『デフォルトのメモ/フッター』に、『当事業者は適格請求書発行事業者です(登録番号 T1234567890123)』を記載
- プレビューで実際のPDF表示を確認 → 保存
11-4. ステップC:消費税を正しく載せる
Stripe Taxを有効化すると、商品ごとの税区分(標準10% / 軽減8% / 非課税)に応じて自動計算され、請求書PDFにも内訳として印字されます。日本のSaaS/デジタル商材は基本『標準10%・内税 or 外税』のどちらかを最初に決めて、商品作成時に統一しましょう。
- Stripeダッシュボード → 設定 → 税金(Tax)→ 日本を有効化
- 商品ごとに『税コード(Tax code)』を設定(SaaSなら “SaaS - business use”)
- Checkout Session作成時に `automatic_tax: { enabled: true }` を渡す
- テスト購入し、PDFに『消費税(10%) ¥◯◯』が出ることを確認
// src/lib/billing.functions.ts(抜粋)
const session = await stripe.checkout.sessions.create({
mode: "subscription",
line_items: [{ price: priceId, quantity: 1 }],
customer_email: data.email, // ← 領収書メール送信に必須
client_reference_id: data.userId,
automatic_tax: { enabled: true }, // ← 消費税の自動計算
invoice_creation: { enabled: true }, // ← 都度払いでも請求書PDFを生成
success_url: `${origin}/billing/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${origin}/pricing`,
});11-5. ステップD:購入者が自分でPDFを再ダウンロードできるようにする
購入者から『領収書をもう一度送って』と毎回頼まれると運用がパンクします。Customer Portalを開放しておけば、購入者が自分でログインして過去全件のPDFをダウンロードできます。
Lovableチャットに次の一文を投げるだけで、ボタン1つで開く実装が入ります。
/account ページに『領収書・請求書をダウンロード』ボタンを追加して。クリックするとStripe Customer Portalのセッションを作って遷移する。戻り先は /account に。// src/lib/billing.functions.ts
export const openBillingPortal = createServerFn({ method: "POST" })
.inputValidator((d) => z.object({ customerId: z.string() }).parse(d))
.handler(async ({ data }) => {
const portal = await stripe.billingPortal.sessions.create({
customer: data.customerId,
return_url: `${process.env.APP_URL}/account`,
});
return { url: portal.url };
});11-6. ステップE:宛名(会社名)を入れた領収書を出したい場合
BtoBで『〇〇株式会社御中』の宛名入り領収書/請求書を要求されることがあります。Stripeでは“顧客(Customer)”オブジェクトに会社名と住所を持たせると、それがPDFの宛名欄に出ます。
- Checkout時に『請求先住所を収集する』をON(`billing_address_collection: 'required'`)
- 『顧客名(会社名)の入力欄を表示』する設定もON
- Customer Portalで購入者自身が後から会社名・住所を変更できるようにしておく
const session = await stripe.checkout.sessions.create({
mode: "subscription",
line_items: [{ price: priceId, quantity: 1 }],
customer_email: data.email,
billing_address_collection: "required", // 住所必須
custom_fields: [{ // 会社名/宛名を任意で取得
key: "company_name",
label: { type: "custom", custom: "会社名(請求書の宛名)" },
type: "text",
optional: true,
}],
automatic_tax: { enabled: true },
invoice_creation: { enabled: true },
// ...
});11-7. よくある質問
実例ケーススタディ:個人事業主の月額サブスク導入を半日で#
- Stripeコネクタを有効化、テストモードのまま開発
- Productを『プレミアム会員』、Priceを『月額1,500円・JPY』で作成
- Lovableに『Stripe Checkoutに飛ばす購読ボタンを /pricing に。成功したら /thanks に戻る』と依頼
- Webhook(checkout.session.completed と customer.subscription.updated)で profiles.is_subscribed を更新
- 本番モードに切り替え、APIキー差し替え、Webhook URLを本番に再設定
つまずきポイント集#
- 症状:Webhookが届かない → 対処:本番URLとシークレットを再登録。署名検証を必ず実装(process.env.STRIPE_WEBHOOK_SECRET)
- 症状:購読キャンセル後も使えてしまう → 対処:customer.subscription.deleted で is_subscribed=false に
- 症状:日本円で『1,500』が『1500.00円』と表示される → 対処:JPYは最小単位なし。Stripe側で1500を入れる(150,000ではない)
- 症状:返金時に領収書が二重発行される → 対処:CreditNoteで対応。手動で領収書を再送しない
FAQ追加#
Q. PaddleとStripeどっちが良い?
海外販売で消費税・VATを丸投げしたいならPaddle、国内中心で柔軟に作りたいならStripeが定番。インボイス対応はStripeでも国内対応が進んでおり、本サイト記事でテンプレート整備の手順を紹介しています。
Q. 売上ダッシュボードは作るべき?
Stripeダッシュボードで十分なケースが多数。社内KPI(チャーン率、LTV)が必要なら、daily snapshotをBigQuery/Sheetsに送って可視化が楽です。
関連記事
※ 本記事は非公式の日本語ガイドです。最新情報は公式ドキュメントをご確認ください。