summaryrefslogtreecommitdiff
path: root/apps/web/app/api/billing/create-portal-session/route.ts
blob: 3832c0d479bc367d8da87f632f3607c7cb5e6efe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import { NextResponse } from "next/server"
import { headers } from "next/headers"
import { createSupabaseServerClient } from "@/lib/supabase/server"
import { getStripe } from "@/lib/stripe"
import { rateLimit } from "@/lib/rate-limit"

export async function POST() {
  const supabaseClient = await createSupabaseServerClient()
  const {
    data: { user },
  } = await supabaseClient.auth.getUser()

  if (!user) {
    return NextResponse.json({ error: "Not authenticated" }, { status: 401 })
  }

  const rateLimitResult = rateLimit(`portal:${user.id}`, 10, 60_000)
  if (!rateLimitResult.success) {
    return NextResponse.json({ error: "Too many requests" }, { status: 429 })
  }

  const { data: profile, error: profileError } = await supabaseClient
    .from("user_profiles")
    .select("stripe_customer_identifier")
    .eq("id", user.id)
    .single()

  if (profileError || !profile) {
    return NextResponse.json(
      { error: "Failed to load profile" },
      { status: 500 }
    )
  }

  if (!profile.stripe_customer_identifier) {
    return NextResponse.json(
      { error: "No billing account found" },
      { status: 400 }
    )
  }

  const headersList = await headers()
  const origin = headersList.get("origin") || "http://localhost:3000"

  const portalSession = await getStripe().billingPortal.sessions.create({
    customer: profile.stripe_customer_identifier,
    return_url: `${origin}/reader/settings`,
  })

  return NextResponse.json({ url: portalSession.url })
}