Skip to main content
This endpoint lets authenticated users open Polar’s self-serve billing portal to update payment methods, download invoices, or cancel subscriptions.
  • Endpoint: GET /api/portal
  • File Location: src/app/api/portal/route.ts
  • Authentication: Required (Supabase session)

Request

No body or query parameters. The request must include the Supabase auth cookies.

Response

Use window.location.href = url to redirect the browser.

Error Responses

StatusBodyDescription
401{ "error": "Unauthorized" }User not signed in
500{ "error": "Something went wrong" }Unexpected failure (see server logs)
500{ "error": "No subscription found" }No polar_customer_id saved in user_subscriptions

How It Works

1

Fetch Supabase user

CustomerPortal receives a getCustomerId callback. The route reuses createClient() to read the current Supabase user. If no session exists, it throws "Unauthorized".
2

Lookup Polar customer

After getting the user, the route queries user_subscriptions for polar_customer_id. Webhooks populate this field when subscriptions are created or updated.
3

Create portal session

The helper calls Polar’s API with your POLAR_ACCESS_TOKEN and returns a portal URL scoped to that customer. The response is serialized as { url } so the client can redirect.

Implementation

src/app/api/portal/route.ts

Frontend Integration

Troubleshooting

Ensure the webhook has created a user_subscriptions row with polar_customer_id. Run a test checkout if the row is missing.
The request must include Supabase auth cookies. If you call this from the client, pass credentials: 'include'.