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
window.location.href = url to redirect the browser.
Error Responses
| Status | Body | Description |
|---|---|---|
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
No subscription found
No subscription found
Ensure the webhook has created a
user_subscriptions row with polar_customer_id. Run a test checkout if the row is missing.401 Unauthorized
401 Unauthorized