Claude Code के साथ Stripe
Claude Code का उपयोग करके stripe सीखें। Practical tips और code examples शामिल हैं।
Stripesubscriptionimplementationको Claude Code से Efficient बनाएं
subscription課金はSaaSビジネスの根幹 है।プラン変更、トライアル、請求management、Webhookprocessing आदि考慮すべき点がज़्यादाですが、Claude Code का उपयोग करकेStripeのベストプラクティスに沿ったimplementationをefficiently進められ है।
プラン定義とCheckoutセッション
> Stripesubscriptionをimplement करो。
> Free / Pro / Enterprise の3プランで、
> トライアル期बीच14日बीच、プラン変更・キャンセルsupport、
> Webhookでの状態syncも含めて。
// 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: ['基本features', '3Project'] },
pro: { name: 'Pro', priceId: process.env.STRIPE_PRO_PRICE_ID!, features: ['全features', '無制限Project', '優先サポート'] },
enterprise: { name: 'Enterprise', priceId: process.env.STRIPE_ENT_PRICE_ID!, features: ['全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プランにsubscriptionは不要です');
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;
}
Webhookprocessing
// 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 });
}
プラン変更processing
// 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('アクティブなsubscriptionがありません');
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('アクティブなsubscriptionがありません');
// 期बीच終了時にキャンセル(即時ではない)
await stripe.subscriptions.update(sub.stripeSubscriptionId, {
cancel_at_period_end: true,
});
}
顧客ポータル
Stripeの顧客ポータルを使えば、プラン変更・支払い方法のupdate・請求書の閲覧を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;
}
関連記事
決済全般के बारे मेंはStripe決済のintegrationガイド、authentication周りはauthenticationfeaturesのimplementationदेखें。
Stripeの公式ガイド(stripe.com/docs/billing)も必ずconfirm करें।
Related Posts
Claude Code से अपने Side Projects को Supercharge कैसे करें [Examples के साथ]
Claude Code से personal development projects को dramatically speed up करना सीखें। Real-world examples और idea से deployment तक practical workflow शामिल है।
Claude Code से Refactoring कैसे Automate करें
Claude Code से efficiently code refactoring automate करना सीखें। Real-world projects के लिए practical prompts और concrete refactoring patterns शामिल हैं।
Claude Code के साथ Complete CORS Configuration Guide
Claude Code का उपयोग करके complete CORS configuration guide सीखें। Practical tips और code examples शामिल हैं।