Reputation: 157
I am trying to get an integration with the stripe customer portal working in my react app so that when the user clicks a button it opens the customer portal and they are able to manage their subscriptions.
Currently I have the following set up to achieve this:
const stripe = require('stripe')("pk_live_xxxxxxxxxxxxxxxxxxxxx");
const [session, setSession] = useState();
useEffect(() => {
console.log('loading in stripe')
const doIt = async () => {
const session = await stripe.billingPortal.sessions.create({
customer: stripeId,
});
console.log("session is ", session)
setSession(session);
};
doIt();
}, []);
And the button to open the portal is as follows:
return (
<>
{session && session.url &&
<form method="POST" action={session.url}>
<button type="submit" className="Button">
Membership
</button>
</form>}
</>
);
The issue I am having is that the button doesn't show on the page so I am unable to click it to go to the customer portal.
Upvotes: 1
Views: 795
Reputation: 1
@Peter Bonnebaigt
Mistake: You are using a client-side publishable key (pk_live_...) to call stripe.billingPortal.sessions.create(), which requires a server-side secret key (sk_live_...). This is both invalid (publishable keys cannot perform API actions) and unsafe (secret keys must never be exposed in client-side code).
Solution:
Step 1: Create a Backend Endpoint Use a server (e.g., Node.js/Express) to securely create the Stripe Billing Portal session:
// Server (e.g., Node.js/Express)
const express = require('express');
const stripe = require('stripe')('sk_live_xxxxxxxxxxxxx'); // Use your secret key
const app = express();
app.use(express.json());
app.post('/create-portal-session', async (req, res) => {
try {
const session = await stripe.billingPortal.sessions.create({
customer: req.body.customerId, // Pass customer ID from client
return_url: 'https://your-website.com/dashboard' // Optional
});
res.json({ url: session.url });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
Step 2: Update Your React Component Fetch the portal URL from your backend instead of using Stripe directly in the client:
// React Component
import React, { useState, useEffect } from 'react';
const PortalButton = ({ stripeId }) => {
const [portalUrl, setPortalUrl] = useState(null);
useEffect(() => {
const fetchPortalUrl = async () => {
try {
const response = await fetch('/create-portal-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ customerId: stripeId }), // Send Stripe customer ID
});
const data = await response.json();
setPortalUrl(data.url);
} catch (err) {
console.error('Failed to create portal session:', err);
}
};
if (stripeId) fetchPortalUrl();
}, [stripeId]);
return (
portalUrl && (
<a href={portalUrl} className="Button">
Manage Membership
</a>
)
);
};
Upvotes: 0
Reputation: 844
It could be due to your conditional failing. Can you log your session
object and see if it indeed has the values that you're looking for?
Upvotes: 0