Stripe Customer Portal: Self-Service Billing Management for Users
In this tutorial, you will learn about Stripe Customer Portal: Self. We cover key concepts, practical examples, and best practices to help you master this topic.
Stripe Customer Portal provides a pre-built, hosted UI where customers manage their billing — update payment methods, view invoices, change plans, cancel subscriptions, and download receipts.
What You'll Learn
How to configure and redirect customers to the Stripe Customer Portal, customize available features, handle redirects back to your app, and sync portal actions via Webhooks.
Why It Matters
Billing support tickets are expensive. Customer Portal lets users manage subscriptions without contacting support. DodaTech reduced billing-related support tickets by 70% after implementing the portal.
Real-World Use
A customer wants to update their credit card. Instead of emailing support, they click "Manage Billing" in the app, get redirected to the Stripe portal, update their card, and return — all in under 2 minutes.
flowchart LR
A["User Clicks\nManage Billing"] --> B["Server Creates\nPortal Session"]
B --> C["Redirect to\nbilling.stripe.com"]
C --> D["User Manages\nPayment Methods"]
C --> E["User Views\nInvoices"]
C --> F["User Changes\nPlan"]
D --> G["Redirect Back\nto Your App"]
style A fill:#dbeafe,stroke:#2563eb
style C fill:#6772e5,color:#fff
style G fill:#bbf7d0,stroke:#16a34a
Creating a Portal Session
import stripe
stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
def create_portal_session(customer_id):
session = stripe.billing_portal.Session.create(
customer=customer_id,
return_url="https://dodatech.com/account/billing"
)
print(f"Portal Session: {session.id}")
print(f"URL: {session.url}")
return session.url
# Redirect customer to the returned URL
portal_url = create_portal_session("cus_abc123")
# Expected output:
# Portal Session: psess_1MqwertyABC123
# URL: https://billing.stripe.com/p/session/abc123...
Customizing the Portal
# Configure in Stripe Dashboard:
# Settings > Customer Portal
# Features you can enable/disable:
# - Update payment methods
# - View invoices and receipts
# - Change subscription plans (with defined prices)
# - Cancel subscriptions
# - Update billing information
# - View subscription history
# Code example: configure available products for plan changes
# In Dashboard: Customer Portal > Products > Select which products
# customers can switch between
def configure_portal_features():
# Configure which subscription items can be swapped
# This is done in the Dashboard, not code
config = {
"allowed_plan_changes": True,
"available_plans": ["pro_monthly", "pro_yearly", "enterprise_monthly"],
"allow_payment_method_updates": True,
"allow_subscription_cancellation": True,
"cancellation_reasons": [
"Too expensive",
"Missing features",
"Not using enough",
"Other"
]
}
print("Portal features configured")
return config
Portal with Existing Customer
def find_or_create_customer(email, name):
# Check if customer exists
customers = stripe.Customer.list(email=email, limit=1)
if customers.data:
customer = customers.data[0]
print(f"Existing customer: {customer.id}")
return customer
# Create new customer
customer = stripe.Customer.create(
email=email,
name=name,
metadata={"source": "signup"}
)
print(f"Created customer: {customer.id}")
return customer
def create_portal_for_user(user_email, user_name):
customer = find_or_create_customer(user_email, user_name)
portal_url = create_portal_session(customer.id)
return portal_url
url = create_portal_for_user("alice@example.com", "Alice Smith")
# Expected output: Existing customer: cus_abc123
Handling Portal Events
# Stripe sends webhook events for portal actions:
# - customer.subscription.updated (plan change)
# - customer.subscription.deleted (cancellation)
# - customer.updated (payment method change)
@app.route("/stripe/webhook", methods=["POST"])
def handle_portal_events():
event = stripe.Webhook.construct_event(
request.get_data(), request.headers.get("Stripe-Signature"), endpoint_secret
)
if event["type"] == "customer.subscription.updated":
sub = event["data"]["object"]
customer_id = sub["customer"]
status = sub["status"]
if sub.get("cancel_at_period_end"):
print(f"Customer {customer_id} set subscription to cancel")
flag_for_cancellation(customer_id)
else:
print(f"Customer {customer_id} changed plan")
sync_plan(customer_id, sub["items"]["data"][0]["price"]["id"])
return jsonify({"status": "ok"}), 200
Common Mistakes
1. Not Setting return_url
Without return_url, customers see a generic Stripe page after managing billing. Always provide a return URL to your app.
2. Over-Restricting Available Actions
If the portal only lets users update payment methods, they'll still contact support for cancellations. Enable common self-service actions.
3. Ignoring Webhook Events from Portal
When a user changes their plan in the portal, Stripe sends webhooks. Sync these changes to your database to keep customer records accurate.
4. Creating Portals Without a Customer Record
The portal requires a Stripe Customer object. If you haven't created one during checkout, create it before redirecting to the portal.
5. Not Handling Customer Portal Errors
Rarely, Stripe may return errors for portal sessions (invalid customer, rate limited). Handle these gracefully and offer alternative support channels.
Practice Questions
- What is the Stripe Customer Portal?
- How do you redirect a customer to the portal?
- What actions can customers perform in the portal?
- How do you sync portal actions with your database?
Answers:
- A hosted UI where customers manage their billing details — payment methods, invoices, subscription plans, and cancellation.
- Create a
billing_portal.Sessionwith the customer ID, get the URL, and redirect the customer to it. - Update payment methods, view invoices/receipts, change subscription plans, cancel subscriptions, update billing information.
- Listen for webhook events (
customer.subscription.updated,customer.updated) and sync the changes to your database.
Challenge: Build a customer billing management flow: find or create a Stripe Customer, configure the portal (allow plan changes and cancellation), create a portal session with return URL, redirect the customer, and handle portal webhook events to sync plan changes.
FAQ
Mini Project
Build a complete customer self-service billing system: create portal session for authenticated users, configure available actions (update card, change plan, cancel), handle return redirect, Process portal webhook events (plan changes, cancellations), and sync subscription changes to your user database.
What's Next
Refunds — process full and partial refunds.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro