import { NextRequest, NextResponse } from 'next/server'; import { cookies } from 'next/headers'; import { stripe } from '@/lib/stripe'; import { db } from '@/lib/db'; import { rateLimit, getClientIdentifier, RateLimits } from '@/lib/rateLimit'; export async function POST(request: NextRequest) { try { const userId = cookies().get('userId')?.value; // Rate Limiting (user-based) const clientId = userId || getClientIdentifier(request); const rateLimitResult = rateLimit(clientId, RateLimits.STRIPE_CANCEL); if (!rateLimitResult.success) { return NextResponse.json( { error: 'Too many requests. Please try again later.', retryAfter: Math.ceil((rateLimitResult.reset - Date.now()) / 1000) }, { status: 429, headers: { 'X-RateLimit-Limit': rateLimitResult.limit.toString(), 'X-RateLimit-Remaining': rateLimitResult.remaining.toString(), 'X-RateLimit-Reset': rateLimitResult.reset.toString(), } } ); } if (!userId) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } // Get user with subscription info const user = await db.user.findUnique({ where: { id: userId }, select: { stripeSubscriptionId: true, plan: true, }, }); if (!user) { return NextResponse.json({ error: 'User not found' }, { status: 404 }); } // Already on free plan if (user.plan === 'FREE') { return NextResponse.json({ error: 'Already on free plan' }, { status: 400 }); } // No active subscription if (!user.stripeSubscriptionId) { // Just update plan to FREE if somehow plan is not FREE but no subscription await db.user.update({ where: { id: userId }, data: { plan: 'FREE', stripePriceId: null, stripeCurrentPeriodEnd: null, }, }); return NextResponse.json({ success: true }); } // Cancel the Stripe subscription await stripe.subscriptions.cancel(user.stripeSubscriptionId); // Update user plan to FREE await db.user.update({ where: { id: userId }, data: { plan: 'FREE', stripeSubscriptionId: null, stripePriceId: null, stripeCurrentPeriodEnd: null, }, }); return NextResponse.json({ success: true }); } catch (error) { console.error('Error canceling subscription:', error); return NextResponse.json( { error: 'Failed to cancel subscription' }, { status: 500 } ); } }