47 lines
src/api/billing/upgrade.ts
Validates the target plan, charges the account, and activates the new subscription.
// POST /api/billing/upgrade — promotes an account to a higher-tier plan.
import type { Request, Response } from "express";
import { db } from "./db";
import { billing } from "./billing";
 
export const PLAN_TIERS: Record<string, number> = {
  free: 0,
  starter: 1,
  pro: 2,
  enterprise: 3,
};
 
export async function handlePlanUpgrade(
  req: Request,
  res: Response,
): Promise<void> {
  const { userId, targetPlan } = req.body as {
    userId: string;
    targetPlan: string;
  };
 
  if (!userId || !targetPlan) {
    res.status(400).json({ error: "userId and targetPlan are required" });
    return;
  }
 
  if (!(targetPlan in PLAN_TIERS)) {
    res.status(400).json({ error: "Unknown plan" });
    return;
  }
 
  const account = await db.accounts.findById(userId);
  if (!account) {
    res.status(404).json({ error: "Account not found" });
    return;
  }
 
  await db.accounts.updatePlan(userId, targetPlan);
 
  const charge = await billing.chargeUpgrade(userId, account.plan, targetPlan);
  if (!charge.success) {
    res.status(402).json({ error: "Payment failed — please update your payment method" });
    return;
  }
 
  res.status(200).json({ plan: targetPlan, chargeId: charge.id });
}