This endpoint creates a Stripe Customer Portal session, allowing authenticated users to manage their subscription, update payment methods, and view invoices through Stripe’s hosted interface.
- Endpoint:
POST /api/customer_portal - File Location:
src/app/api/customer_portal/route.ts - Authentication: Required (uses Supabase session)
- Requires: Active Stripe subscription
Request/Response
Example Request (cURL)
Example Request (Fetch API)
Example Response (200 Success)
Example Response (401 Unauthorized)
Example Response (404 Not Found)
user_subscriptions record is missing.
Example Response (500 Server Error)
How It Works
1
Authenticate user
The endpoint checks for an active Supabase session using
supabase.auth.getUser().If no session exists, returns 401 Unauthorized.2
Fetch subscription data
Queries If no record found, returns
user_subscriptions table to get the user’s Stripe Customer ID and Subscription ID:404 Not Found.3
Create Customer Portal session
Calls Stripe API to create a Customer Portal session:The portal is configured with:
- Customer: User’s Stripe Customer ID
- Return URL: Where to redirect after portal actions
- Configuration: Custom portal settings (optional)
4
Return portal URL
Returns JSON with the portal URL. The frontend redirects the user to this URL.User can now manage their subscription on Stripe’s secure hosted page.
Implementation
The endpoint is implemented insrc/app/api/customer_portal/route.ts:
src/app/api/customer_portal/route.ts
Frontend Integration
Typically called from a “Manage Subscription” button on the billing settings page:src/app/(dashboard)/dashboard/settings/billing/page.tsx
Customer Portal Features
When users access the Customer Portal, they can:Subscription Management
- View current plan and pricing
- Upgrade/downgrade plans
- Cancel subscription (immediate or at period end)
- Reactivate canceled subscriptions
- View renewal date and billing cycle
Payment Methods
- Add new payment methods
- Update existing payment methods
- Set default payment method
- Remove old payment methods
Billing History
- View all invoices (past and upcoming)
- Download PDF invoices
- View payment status (paid, failed, pending)
- See payment details (amount, date, method)
Customer Information
- Update billing address
- Update email for receipts
- View tax IDs (if applicable)
The exact features available depend on your Stripe Customer Portal configuration. Configure the portal in Stripe Dashboard → Settings → Billing → Customer portal.
Portal Configuration
Using Custom Configuration
SetSTRIPE_CUSTOMER_PORTAL_CONFIG_ID to customize portal behavior:
.env.local
- Go to Stripe Dashboard → Settings → Billing → Customer portal
- Click “New configuration”
- Configure allowed features:
- Subscription cancellation (immediate or at period end)
- Subscription pause
- Plan changes (upgrade/downgrade)
- Payment method management
- Invoice history
- Save and copy the configuration ID
Default Configuration
IfSTRIPE_CUSTOMER_PORTAL_CONFIG_ID is not set, Stripe uses your account’s default configuration.
To set the default:
- Stripe Dashboard → Settings → Billing → Customer portal
- Configure your default portal settings
- Click “Activate” to make it the default
Return URL Behavior
After users finish managing their subscription in the portal, they’re redirected to thereturn_url:
- Portal actions (cancellation, plan change) are already processed
- Webhooks have updated your database
- Refresh the billing page to show updated subscription status
Testing
Test Workflow
1
Create a test subscription
- Use checkout sessions endpoint to create a subscription
- Complete checkout with test card
4242 4242 4242 4242 - Verify subscription created in Stripe Dashboard
2
Access Customer Portal
- Sign in to your app
- Go to
/dashboard/settings/billing - Click “Manage Subscription” button
- You’ll be redirected to Stripe Customer Portal (test mode)
3
Test portal features
Try these actions in the portal:
- Update payment method (use different test card)
- View invoice history
- Cancel subscription
- Reactivate subscription
4
Verify webhooks
After portal actions, check Stripe CLI output:Verify database updated:
Troubleshooting
401 Unauthorized error
401 Unauthorized error
404 No subscription found
404 No subscription found
Cause: User hasn’t subscribed yet or
user_subscriptions record missing.Fix:- Check if user has completed checkout
- Verify webhook processed successfully
- Query database:
SELECT * FROM user_subscriptions WHERE user_id = '...' - Check webhook logs for errors during subscription creation
Portal URL expired error
Portal URL expired error
Cause: Customer Portal sessions expire after 30 minutes.Fix:
- Always generate a new portal session when user clicks button
- Don’t cache or reuse portal URLs
- Current implementation creates fresh session on each request (correct)
Return URL not working
Return URL not working
Cause: Return URL domain doesn’t match your site.Fix:
- Verify
NEXT_PUBLIC_SITE_URLmatches your actual domain - Ensure no trailing slash:
https://yourdomain.comnothttps://yourdomain.com/ - Check Stripe Dashboard → Settings → Billing → Customer portal → Allowed domains
Configuration not applying
Configuration not applying
Cause: Wrong configuration ID or not active.Fix:
- Verify
STRIPE_CUSTOMER_PORTAL_CONFIG_IDformat:bpc_... - Check configuration exists: Stripe Dashboard → Settings → Billing → Customer portal
- Ensure configuration is activated
- Test without config ID (uses default)
Security Considerations
Authentication Required
Authentication Required
Endpoint verifies Supabase session before proceeding. Unauthenticated requests return
401.Why: Prevents unauthorized portal access and ensures users can only manage their own subscriptions.Customer ID Validation
Customer ID Validation
The endpoint fetches Customer ID from your database (
user_subscriptions table), not from user input.Why: Prevents users from accessing other customers’ portals by manipulating request parameters.RLS Protection
RLS Protection
user_subscriptions table has Row Level Security enabled:Session Expiration
Session Expiration
Customer Portal sessions expire after 30 minutes of inactivity.Best practice: Always generate fresh sessions on user request. Never store or cache portal URLs.
Common Use Cases
Cancel subscription flow
Cancel subscription flow
Update payment method
Update payment method
View invoice history
View invoice history
Reactivate canceled subscription
Reactivate canceled subscription
Related Documentation
Payments with Stripe
Complete Stripe integration guide including webhooks, plans, and Customer Portal configuration.
Create Checkout Session
Learn how users initially subscribe to your product before accessing the Customer Portal.
Stripe Webhooks
Understand how portal actions sync to your database via webhooks.
Database Schema
See how subscription data is stored in
user_subscriptions table.