Gazebo
    ServicesAgentsDocsSpecWritingPricing
    Log inSign up
    Log in
    GazeboWorkflowsStripeHow to Configure the Stripe Customer Portal

    Workflow

    How to Configure the Stripe Customer Portal

    Let subscribers manage their own billing with Stripe's hosted portal.

    Last updated June 2026

    That's 4 steps.

    Describe it once — Gazebo generates a plan, you approve it, it runs.

    "Configure the Stripe Customer Portal for my subscription product"

    Let Gazebo handle this

    What you're doing and why it's painful

    The Stripe Customer Portal is a Stripe-hosted page where your subscribers can manage their own billing: update payment methods, upgrade or downgrade their plan, view past invoices, and cancel. You don't build any of this — Stripe hosts it and you just redirect users there.

    The pain: the portal must be configured in the Stripe Dashboard before it works. Without configuration, users who land on the portal URL see an error. The configuration isn't where you'd expect it, and it's easy to miss that you need to enable specific features (like cancellation) before they show up.

    Prerequisites

    • A Stripe account with at least one active Product and subscription Price
    • Your server can create a portal session via the Stripe API

    Step 1 — Configure the Customer Portal in the Dashboard

    1. Log in to the Stripe Dashboard
    2. Go to Settings → Billing → Customer portal (or search "Customer portal" in the top search bar)
    3. Under Functionality, enable what you want subscribers to be able to do:
      • Payment methods — update or add cards
      • Invoice history — view and download past invoices
      • Update subscriptions — change quantity or plan (optional)
      • Cancel subscriptions — let users self-cancel
    4. Under Cancellation options (if you enabled cancellation):
      • Choose whether to cancel immediately or at end of billing period
      • Optionally configure a cancellation survey
    5. Under Business information, add your support URL and privacy policy URL — shown in the portal header
    6. Click Save

    Step 2 — Create a portal session in your server

    When a user clicks "Manage billing" in your app, your server creates a portal session and redirects the user there:

    import Stripe from 'stripe';
    const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
    
    app.post('/api/billing/portal', requireAuth, async (req, res) => {
      const user = req.user; // your authenticated user
      
      // You need the user's Stripe customer ID — store this when they first subscribe
      const session = await stripe.billingPortal.sessions.create({
        customer: user.stripeCustomerId,
        return_url: 'https://yourdomain.com/settings',
      });
    
      res.redirect(session.url);
    });
    

    The return_url is where users land when they click the back button in the portal.

    Step 3 — Add a "Manage billing" button in your app

    In your settings or account page, add a button that calls your server endpoint:

    // React example
    function ManageBillingButton() {
      const handleClick = async () => {
        const res = await fetch('/api/billing/portal', { method: 'POST' });
        // The server redirects, so just follow the response location
        window.location.href = res.url;
      };
      
      return (
        <button onClick={handleClick}>
          Manage billing
        </button>
      );
    }
    

    Step 4 — Store the Stripe Customer ID

    The portal session requires a customer ID. Make sure you're storing this when users first subscribe.

    When handling a checkout.session.completed webhook event, extract and save the customer ID:

    case 'checkout.session.completed': {
      const session = event.data.object as Stripe.Checkout.Session;
      // Store session.customer (the customer ID) in your database
      await db.user.update({
        where: { id: session.client_reference_id },
        data: { stripeCustomerId: session.customer as string },
      });
      break;
    }
    

    Set client_reference_id to your user's ID when creating the Checkout session so you can match the webhook back to a user.


    Testing it locally

    Use the Stripe CLI to confirm the portal is reachable before deploying:

    stripe login
    stripe open --dashboard billing
    

    Or create a test portal session directly and open the URL in your browser — Stripe test mode customers work the same as live customers for portal testing.


    Common errors and gotchas

    No such customer error The customer ID doesn't exist in Stripe — either it was created in test mode and you're using it in live mode (or vice versa), or you're passing the wrong ID. Check that you're using the correct Stripe environment and that the ID starts with cus_.

    Portal shows a blank error page on load The portal hasn't been activated in the Dashboard yet. Complete Step 1 — the portal must be turned on before any session creation will work. This is the most common cause of a working portal session URL returning an error screen.

    Cancel subscriptions option not showing in the portal You need to explicitly enable "Cancel subscriptions" in the portal settings (Step 1 → Functionality → Cancel subscriptions). It's disabled by default.

    return_url must be an absolute URL Pass the full URL including https:// — relative paths like /settings will fail validation.

    Portal loads but shows no subscriptions The customer has no active subscriptions in Stripe. If you're testing, make sure you created the subscription against the same customer ID you're passing to the portal session. Also check you're not mixing test-mode customers with live-mode sessions.

    Changes to portal settings don't apply immediately After saving changes to portal configuration in the Dashboard, it can take a few seconds to propagate. Reload and create a new portal session rather than refreshing an existing one.

    configuration parameter required for multiple portal configs If you have more than one Customer Portal configuration saved (e.g., different configs for different product lines), you must pass the configuration ID explicitly to billingPortal.sessions.create. Omitting it defaults to the active configuration.

    Skip the manual steps.

    Describe it once — Gazebo generates a plan, you approve it, it runs.

    "Configure the Stripe Customer Portal for my subscription product"

    Let Gazebo handle this
    ← All Stripe workflowsAll workflows
    Gazebo

    IAM for AI agents. Scoped credentials, access policies, and audit trails — without rotating keys.

    Product

    • Pricing
    • Status

    Explore

    • Services
    • Agents
    • Workflows
    • Integrations

    Content

    • Writing
    • Topics
    • Blog
    • Docs

    Free Tools

    • Scanner

    Company

    • About
    • [email protected]
    • [email protected]

    © 2026 Gazebo. All rights reserved.

    PrivacyTermsSecurity