Integrating the customer portal

Learn how to configure the customer portal and make it available to your customers.

Follow these steps to integrate your application with the customer portal to enable your customers to manage their subscriptions and billing details:

  1. Configure the portal’s features and UI.
  2. Implement a redirect to integrate the portal with your application.
  3. Listen to webhooks to receive updates to customers’ subscriptions and payment methods.
  4. Go live to use the portal in your production environment.

1 Configure the portal

Prior to integrating the customer portal, you must configure its functionality and branding in the Stripe Dashboard. These settings determine the actions that your users can take using the portal. Its features depend on your product and price catalog, so there are different settings for live mode and test mode. Navigate to the portal settings to configure the portal.

Setting Description
Update subscriptions Allow customers to upgrade and downgrade their subscriptions (customers can preview the changes before confirming them). You can also enable prorations when changes are made.
Cancel subscriptions Allow customers to cancel their subscriptions, immediately or at end of billing period. The latter allows customers to reactivate their subscriptions at any time before the end of the period.
Update payment methods Allow customers to manage their payment methods like adding and removing cards, and setting a new default payment method.
View billing history Allow customers to view billing history and download invoices.

Set a product catalog

If you allow customers to change their subscriptions, you also need to set a product catalog. This includes the products and prices that your customers can upgrade or downgrade to. The portal displays the following attributes of your product catalog:

  • Product name and description—these attributes are editable in the Dashboard and API.
  • Price amount, currency, and billing interval—these attributes are immutable and can only be set on creation in the Dashboard and API.


Changing subscriptions in the portal is only supported for charge_automatically subscriptions with a single licensed price and a fixed quantity of 1. Subscriptions that use any of the following cannot be upgraded or downgraded in the portal, but can still be canceled:

Subscriptions attached to schedules cannot be upgraded, downgraded, or canceled.

Update payment method functionality only supports cards. This section only displays cards, and it is hidden if the customer’s default payment method is not a card.

Modifying an account’s portal configuration is only available through the Stripe Dashboard.

Previewing and testing

As you configure the settings, you can preview the portal by clicking the Preview button. This launches a read-only version of the portal so you can see how customers would use it to manage subscriptions and billing details.

After saving the settings, you can launch the portal and test it using a customer in test mode. Navigate to a customer in the Dashboard and then click the ••• button and select Open customer portal.

The portal is automatically localized for a set of languages. To view a localized version of the portal, set your browser’s default language to the language you’d like to preview.

Which languages are supported by the portal?
  • Bulgarian (bg)
  • Czech (cs)
  • Danish (da)
  • Dutch (nl)
  • English (en)
  • Estonian (et)
  • Finnish (fi)
  • French (fr)
  • German (de)
  • Greek (el)
  • Hungarian (hu)
  • Italian (it)
  • Japanese (ja)
  • Latvian (lv)
  • Lithuanian (lt)
  • Malay (ms)
  • Maltese (mt)
  • Norwegian Bokmål (nb-NO)
  • Polish (pl)
  • Portuguese (pt)
  • Romanian (ro)
  • Russian (ru)
  • Simplified Chinese (zh)
  • Slovak (sk)
  • Slovenian (sl)
  • Spanish (es)
  • Swedish (sv)
  • Turkish (tr)

2 Implement a redirect

A portal session is the entry point into the customer portal. It provides a temporary link to the portal specific to each customer. When a customer wants to visit their portal, you create a new portal session and redirect them to the session’s url.

On your site, add a button that customers can click to enter the portal. Use a POST request to create a portal session:

<form method="POST" action="/create_customer_portal_session"> <button type="submit">Manage billing</button> </form>

Next, add an endpoint that creates a portal session and redirects your customers. Make sure to authenticate customers on your site before creating sessions for them. To create a session, you need the customer’s ID and a return_url, which is required if a default return url isn’t set in the Dashboard configuration.

curl \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer=cus_HbgSo0XA8YDrsy \ -d return_url=""
stripe billing_portal sessions create \ --customer=cus_HbgSo0XA8YDrsy \ --return-url=""
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' Stripe::BillingPortal::Session.create({ customer: 'cus_HbgSo0XA8YDrsy', return_url: '', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' stripe.billing_portal.Session.create( customer='cus_HbgSo0XA8YDrsy', return_url='', )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); \Stripe\BillingPortal\Session::create([ 'customer' => 'cus_HbgSo0XA8YDrsy', 'return_url' => '', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; SessionCreateParams params = SessionCreateParams.builder() .setCustomer("cus_HbgSo0XA8YDrsy") .setReturnUrl("") .build(); Session session = Session.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); var session = await stripe.billingPortal.sessions.create({ customer: 'cus_HbgSo0XA8YDrsy', return_url: '', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.BillingPortalSessionParams{ Customer: stripe.String("cus_HbgSo0XA8YDrsy"), ReturnURL: stripe.String(""), } s, _ := session.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new SessionCreateOptions { Customer = "cus_HbgSo0XA8YDrsy", ReturnUrl = "", }; var service = new SessionService(); var session = service.Create(options);

In the response body, there is a url attribute:

{ "id": "pts_1G8ZkbClCIKljWvsk5O2fhg6", "object": "billing_portal.session", "created": 1580854809, "customer": "cus_HbgSo0XA8YDrsy", "livemode": false, "return_url": "", "url": "{SESSION_SECRET}" }

Redirect customers to this URL. For security reasons, URLs expire soon after they’re created so redirect customers immediately.

After the redirect, the customer portal opens and customers can manage their subscriptions and billing details. When customers click the Return to link or your company’s name or logo within the portal, they’re redirected to the return_url. Be careful building logic around the return_url. Some customers might not return to your site, or they might open your site in a new tab, which wouldn’t trigger logic built around the return_url.

3 Listen to webhooks

When subscriptions are upgraded, downgraded, or canceled, you need to ensure that customers receive only the products or services they are actively subscribed to. Stripe sends notifications of these changes to your integration using webhooks. In the Event object, look at the ID for the subscription or the customer to determine which customer the event applies to.

If you haven’t set up a webhook endpoint with Stripe before, you can use the general webhooks documentation to get started and then listen for the the events described below.

Subscription upgrades and downgrades

Listen for the customer.subscription.updated event and check the[0].price attribute to find the price the customer is subscribed to. Then, grant access to the new product.

When a customer uses the portal to upgrade or downgrade a subscription with a trial, the subscription’s trial ends immediately when switching to the new price.

Subscription cancellation

Listen to the customer.subscription.deleted event and then remove the customer’s access to the product.

If you configure the portal to cancel subscriptions at the end of a billing period, listen to the customer.subscription.updated event to be notified of cancellations before they occur. If cancel_at_period_end is true, the subscription will be canceled at the end of its billing period.

If a customer changes their mind, they can reactivate their subscription if the end of the billing period hasn’t occurred yet. When they do this, a customer.subscription.updated event is sent. Check that cancel_at_period_end is false to confirm that they reactivated their subscription.

Payment method updates

Customers can use the portal to add and remove payment methods, and select a new default payment method.

If you have subscriptions that override the customer-level default payment method, customers have the ability to remove this override. Listen to the customer.subscription.updated event and check the default_payment_method attribute when this occurs.

4 Go live

Make sure to test the portal before enabling it in production. If you’re going live with Stripe for the first time, you might also want to work through the Billing testing guide. When you’re ready to go live:

  • Toggle the View test data button off in the Stripe Dashboard.
  • Configure the portal in live mode.
  • Add your webhooks in live mode.

Note that Stripe maintains two distinct sets of the portal configuration: one for live mode and one for test mode. To help you validate your integration, making changes while in one mode does not affect your configuration in the other.

Was this page helpful?
Questions? Contact us.
Developer tutorials on YouTube.
You can unsubscribe at any time. Read our privacy policy.