Your Name 353c3d04ff
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: add billing center and stripe portal management
2026-02-12 12:49:03 +08:00

66 lines
1.9 KiB
TypeScript

import { type NextRequest, NextResponse } from "next/server";
import { auth } from "@/app/(auth)/auth";
import {
createStripeBillingPortalSession,
findStripeCustomerIdByEmail,
StripeRequestError,
} from "@/lib/billing/stripe";
function getBaseUrl(request: NextRequest) {
return (
process.env.AUTH_URL ??
`${request.nextUrl.protocol}//${request.headers.get("host") ?? request.nextUrl.host}`
);
}
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id || !session.user.email) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
if (session.user.type === "guest") {
return NextResponse.json({ error: "Guest user cannot manage subscription" }, { status: 403 });
}
const stripeSecretKey = process.env.STRIPE_SECRET_KEY;
if (!stripeSecretKey) {
return NextResponse.json({ error: "Stripe is not configured" }, { status: 503 });
}
const customerId = await findStripeCustomerIdByEmail({
secretKey: stripeSecretKey,
email: session.user.email,
});
if (!customerId) {
return NextResponse.json({ error: "No Stripe subscription account found" }, { status: 404 });
}
const returnUrl = process.env.STRIPE_BILLING_RETURN_URL
? process.env.STRIPE_BILLING_RETURN_URL
: new URL("/billing", getBaseUrl(request)).toString();
const portalSession = await createStripeBillingPortalSession({
secretKey: stripeSecretKey,
customerId,
returnUrl,
});
return NextResponse.json({
id: portalSession.id,
url: portalSession.url,
});
} catch (error) {
if (error instanceof StripeRequestError) {
return NextResponse.json({ error: error.message }, { status: error.status });
}
console.error("[Billing Portal API] Error:", error);
return NextResponse.json({ error: "Failed to create billing portal session" }, { status: 500 });
}
}