I’m using the Stripe extension in Firebase to create subscriptions in a NextJS web app.
My goal is to create a link for a returning user to edit their payments in Stripe without authenticating again (they are already auth in my web app and Firebase recognizes the auth).
I’m using the test mode of Stripe and I have a test customer and test products.
I’ve tried
-
The Firebase Stripe extension library does not have any function which can just return a billing portal link: https://github.com/stripe/stripe-firebase-extensions/blob/next/firestore-stripe-web-sdk/markdown/firestore-stripe-payments.md
-
Use the NextJS recommended import of Stripe foudn in this Vercel blog
First I setup the import for Stripe-JS: https://github.com/vercel/next.js/blob/758990dc06da4c2913f42fdfdacfe53e29e56593/examples/with-stripe-typescript/utils/get-stripejs.ts
export default function Settings() { import stripe from "../../stripe_utils/get_stripejs" async function editDashboard() { const dashboardLink = await stripe.billingPortal.sessions.create({ customer: "cus_XXX", }) } console.log(dashboardLink.url) return ( <Button onClick={() => editDashboard()}> DEBUG: See payments </Button> ) }
This would result in an error:
TypeError: Cannot read properties of undefined (reading 'sessions')
-
Use the
stripe
library. This seemed like the most promising solution but from what I read this is a backend library though I tried to use on the front end. There were no errors with this approach but I figure it hangs on theawait
import Stripe from "stripe" const stripe = new Stripe(process.env.STRIPE_SECRET) ... const session = await stripe.billingPortal.sessions.create({ customer: 'cus_XXX', return_url: 'https://example.com/account', }) console.log(session.url) // Does not reach here
-
Use a pre-made Stripe link to redirect but the user will have to authenticate on Stripe using their email (this works but I would rather have a short-lived link from Stripe)
<Button component={Link} to={"https://billing.stripe.com/p/login/XXX"}> Edit payment info on Stripe </Button>
-
Using POST HTTPS API call found at https://stripe.com/docs/api/authentication. Unlike the previous options, this optional will register a Stripe Dashboard Log event.
const response = await fetch("https://api.stripe.com/v1/billing_portal/sessions", { method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, *cors, same-origin cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'same-origin', // include, *same-origin, omit headers: { 'Content-Type': 'application/json', 'Authorization': 'bearer sk_test_XXX', 'Content-Type': 'application/x-www-form-urlencoded', }, redirect: 'follow', // manual, *follow, error referrerPolicy: 'no-referrer', // no-referrer, *client body: JSON.stringify(data), // body data type must match "Content-Type" header })
The error is I’m missing some parameter
parameter_missing -customer
. So I’m closer to a resolution but I feel as if I should still be able to make the solution above work.
2
Answers
Given my case, I chose to call the API itself instead of the libraries provided:
You should use Stripe library to create a billing portal session (your 2nd approach), and you might want to check your Dashboard logs and set the endpoint to
/v1/billing_portal/sessions
so that you can see if there are any errors during portal session creation.