import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { db, users, tierDefinitions, eq } from "@epicure/db"; import { requireSession } from "@/lib/api-auth"; import { applyRateLimit } from "@/lib/rate-limit"; import { getStripeClient } from "@/lib/stripe"; const Schema = z.object({ tier: z.enum(["pro", "family"]), interval: z.enum(["month", "year"]), }); export async function POST(req: NextRequest) { const { session, response } = await requireSession(); if (response) return response; const limited = await applyRateLimit(`rl:billing:checkout:${session!.user.id}`, 10, 60); if (limited) return limited; const parsed = Schema.safeParse(await req.json()); if (!parsed.success) { return NextResponse.json({ error: "Validation error", issues: parsed.error.issues }, { status: 400 }); } const stripe = await getStripeClient(); if (!stripe) { return NextResponse.json({ error: "Billing is not configured" }, { status: 400 }); } const tierDef = await db.query.tierDefinitions.findFirst({ where: eq(tierDefinitions.tier, parsed.data.tier) }); const priceId = parsed.data.interval === "year" ? tierDef?.stripePriceIdYearly : tierDef?.stripePriceIdMonthly; if (!priceId) { return NextResponse.json({ error: `No ${parsed.data.interval}ly price configured for ${parsed.data.tier}` }, { status: 400 }); } const [dbUser] = await db.select({ stripeCustomerId: users.stripeCustomerId, email: users.email }).from(users).where(eq(users.id, session!.user.id)).limit(1); const baseUrl = process.env["BETTER_AUTH_URL"] ?? "http://localhost:3000"; const checkoutSession = await stripe.checkout.sessions.create({ mode: "subscription", customer: dbUser?.stripeCustomerId ?? undefined, customer_email: dbUser?.stripeCustomerId ? undefined : dbUser?.email, client_reference_id: session!.user.id, metadata: { userId: session!.user.id }, line_items: [{ price: priceId, quantity: 1 }], allow_promotion_codes: true, success_url: `${baseUrl}/settings/billing?checkout=success`, cancel_url: `${baseUrl}/settings/billing?checkout=canceled`, }); if (!checkoutSession.url) { return NextResponse.json({ error: "Failed to create checkout session" }, { status: 500 }); } return NextResponse.json({ url: checkoutSession.url }); }