Skip to content

Commit 25c20e5

Browse files
authored
fix: Handle personal billing portal on backend (calcom#23521)
1 parent ec8a441 commit 25c20e5

1 file changed

Lines changed: 27 additions & 20 deletions

File tree

  • packages/app-store/stripepayment/api

packages/app-store/stripepayment/api/portal.ts

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next";
22

33
import { WEBAPP_URL } from "@calcom/lib/constants";
44
import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
5+
import logger from "@calcom/lib/logger";
56
import { TeamRepository } from "@calcom/lib/server/repository/team";
67
import prisma from "@calcom/prisma";
78
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
@@ -10,6 +11,21 @@ import { getStripeCustomerIdFromUserId } from "../lib/customer";
1011
import stripe from "../lib/server";
1112
import { getSubscriptionFromId } from "../lib/subscriptions";
1213

14+
const getBillingPortalUrl = async (customerId: string, return_url: string) => {
15+
const log = logger.getSubLogger({ prefix: ["getBillingPortalUrl"] });
16+
try {
17+
const portalSession = await stripe.billingPortal.sessions.create({
18+
customer: customerId,
19+
return_url,
20+
});
21+
22+
return portalSession.url;
23+
} catch (e) {
24+
log.error(`Failed to create billing portal session for ${customerId}: ${e}`);
25+
throw new Error("Failed to create billing portal session");
26+
}
27+
};
28+
1329
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
1430
if (req.method !== "POST" && req.method !== "GET")
1531
return res.status(405).json({ message: "Method not allowed" });
@@ -18,35 +34,29 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
1834

1935
const userId = req.session.user.id;
2036
const teamId = req.query.teamId ? parseInt(req.query.teamId as string) : null;
21-
37+
let return_url = `${WEBAPP_URL}/settings/billing`;
2238
if (!teamId) {
23-
return res.status(400).json({ message: "Team ID is required" });
39+
const customerId = await getStripeCustomerIdFromUserId(userId);
40+
if (!customerId) return res.status(404).json({ message: "CustomerId not found" });
41+
42+
const billingPortalUrl = await getBillingPortalUrl(customerId, return_url);
43+
44+
return res.redirect(302, billingPortalUrl);
2445
}
2546

2647
const teamRepository = new TeamRepository(prisma);
2748
const team = await teamRepository.getTeamByIdIfUserIsAdmin({
2849
teamId,
2950
userId,
3051
});
31-
let return_url = `${WEBAPP_URL}/settings/billing`;
52+
53+
if (!team) return res.status(404).json({ message: "Team not found" });
3254

3355
if (typeof req.query.returnTo === "string") {
3456
const safeRedirectUrl = getSafeRedirectUrl(req.query.returnTo);
3557
if (safeRedirectUrl) return_url = safeRedirectUrl;
3658
}
3759

38-
if (!team) {
39-
const customerId = await getStripeCustomerIdFromUserId(userId);
40-
if (!customerId) return res.status(404).json({ message: "CustomerId not found" });
41-
42-
const portalSession = await stripe.billingPortal.sessions.create({
43-
customer: customerId,
44-
return_url,
45-
});
46-
47-
return res.status(200).json({ url: portalSession.url });
48-
}
49-
5060
const teamMetadataParsed = teamMetadataSchema.safeParse(team.metadata);
5161

5262
if (!teamMetadataParsed.success) {
@@ -71,10 +81,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
7181

7282
if (!customerId) return res.status(400).json({ message: "CustomerId not found in stripe" });
7383

74-
const stripeSession = await stripe.billingPortal.sessions.create({
75-
customer: customerId,
76-
return_url,
77-
});
84+
const billingPortalUrl = await getBillingPortalUrl(customerId, return_url);
7885

79-
res.redirect(302, stripeSession.url);
86+
res.redirect(302, billingPortalUrl);
8087
}

0 commit comments

Comments
 (0)