Stripe with Claude Code
Learn about stripe using Claude Code. Practical tips and code examples included.
Stripeサブスクリプション実装をClaude Codeで効率化する
サブスクリプション課金はSaaSビジネスの根幹です。プラン変更、トライアル、請求管理、Webhook処理など考慮すべき点が多いですが、Claude Codeを使えばStripeのベストプラクティスに沿った実装を効率的に進められます。
プラン定義とCheckoutセッション
> Stripeサブスクリプションを実装して。
> Free / Pro / Enterprise の3プランで、
> トライアル期間14日間、プラン変更・キャンセル対応、
> Webhookでの状態同期も含めて。
// src/lib/subscription.ts
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export const PLANS = {
free: { name: 'Free', priceId: null, features: ['基本機能', '3プロジェクト'] },
pro: { name: 'Pro', priceId: process.env.STRIPE_PRO_PRICE_ID!, features: ['全機能', '無制限プロジェクト', '優先サポート'] },
enterprise: { name: 'Enterprise', priceId: process.env.STRIPE_ENT_PRICE_ID!, features: ['全機能', 'SSO', '専任担当', 'SLA'] },
} as const;
export type PlanKey = keyof typeof PLANS;
export async function createSubscription(userId: string, plan: PlanKey) {
if (plan === 'free') throw new Error('Freeプランにサブスクリプションは不要です');
const customer = await findOrCreateCustomer(userId);
const priceId = PLANS[plan].priceId;
const session = await stripe.checkout.sessions.create({
customer: customer.id,
mode: 'subscription',
line_items: [{ price: priceId!, quantity: 1 }],
subscription_data: { trial_period_days: 14 },
success_url: `${process.env.APP_URL}/dashboard?upgraded=true`,
cancel_url: `${process.env.APP_URL}/pricing`,
metadata: { userId, plan },
});
return session.url;
}
Webhook処理
// src/app/api/webhooks/stripe/route.ts
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';
import { prisma } from '@/lib/prisma';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(request: NextRequest) {
const body = await request.text();
const signature = request.headers.get('stripe-signature')!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch {
return NextResponse.json({ error: 'Invalid signature' }, { status: 400 });
}
switch (event.type) {
case 'customer.subscription.created':
case 'customer.subscription.updated': {
const subscription = event.data.object as Stripe.Subscription;
await prisma.subscription.upsert({
where: { stripeSubscriptionId: subscription.id },
create: {
stripeSubscriptionId: subscription.id,
stripeCustomerId: subscription.customer as string,
status: subscription.status,
plan: subscription.metadata.plan || 'pro',
currentPeriodEnd: new Date(subscription.current_period_end * 1000),
},
update: {
status: subscription.status,
currentPeriodEnd: new Date(subscription.current_period_end * 1000),
},
});
break;
}
case 'customer.subscription.deleted': {
const subscription = event.data.object as Stripe.Subscription;
await prisma.subscription.update({
where: { stripeSubscriptionId: subscription.id },
data: { status: 'canceled' },
});
break;
}
case 'invoice.payment_failed': {
const invoice = event.data.object as Stripe.Invoice;
// 支払い失敗の通知メールを送信
await sendPaymentFailedEmail(invoice.customer as string);
break;
}
}
return NextResponse.json({ received: true });
}
プラン変更処理
// src/lib/subscription.ts(続き)
export async function changePlan(userId: string, newPlan: PlanKey) {
const sub = await prisma.subscription.findFirst({
where: { userId, status: 'active' },
});
if (!sub) throw new Error('アクティブなサブスクリプションがありません');
const stripeSubscription = await stripe.subscriptions.retrieve(
sub.stripeSubscriptionId
);
await stripe.subscriptions.update(sub.stripeSubscriptionId, {
items: [
{
id: stripeSubscription.items.data[0].id,
price: PLANS[newPlan].priceId!,
},
],
proration_behavior: 'create_prorations', // 日割り計算
metadata: { plan: newPlan },
});
}
export async function cancelSubscription(userId: string) {
const sub = await prisma.subscription.findFirst({
where: { userId, status: 'active' },
});
if (!sub) throw new Error('アクティブなサブスクリプションがありません');
// 期間終了時にキャンセル(即時ではない)
await stripe.subscriptions.update(sub.stripeSubscriptionId, {
cancel_at_period_end: true,
});
}
顧客ポータル
Stripeの顧客ポータルを使えば、プラン変更・支払い方法の更新・請求書の閲覧をStripe側のUIに任せられます。
export async function createPortalSession(userId: string) {
const customer = await getCustomerByUserId(userId);
const session = await stripe.billingPortal.sessions.create({
customer: customer.id,
return_url: `${process.env.APP_URL}/settings/billing`,
});
return session.url;
}
Verwandte Artikel
決済全般についてはStripe決済の統合ガイド、認証周りは認証機能の実装をご覧ください。
Stripeの公式ガイド(stripe.com/docs/billing)も必ず確認しましょう。
Related Posts
So beschleunigen Sie Ihre Nebenprojekte mit Claude Code [Mit Beispielen]
Erfahren Sie, wie Sie persönliche Entwicklungsprojekte mit Claude Code drastisch beschleunigen. Inklusive realer Beispiele und eines praktischen Workflows von der Idee bis zum Deployment.
So automatisieren Sie Refactoring mit Claude Code
Erfahren Sie, wie Sie Code-Refactoring mit Claude Code effizient automatisieren. Inklusive praktischer Prompts und konkreter Refactoring-Muster für reale Projekte.
Vollständiger CORS-Konfigurationsleitfaden mit Claude Code
Erfahren Sie alles über die CORS-Konfiguration mit Claude Code. Mit praktischen Tipps und Codebeispielen.