#josephmalam-customer-portal
1 messages · Page 1 of 1 (latest)
Hi @ancient niche , yep I'm using Checkout. For example, the success page could be:
https://website.xyz/thankyou?session_id=cs_test...
Do I save that session_id to the database for the customer and pass it as the form value? (btw, not sure how to access that, I'm using Vue)
Got it. You create a Customer Portal session using a cus_xxx ID, the Checkout Session ID isn't really relevant here
Can you share the ID of an example Checkout Session? cs_test_xxx
Do you mean the full string from the end here?
Yep
cs_test_a1131rMjAeKLN6h134iUGATLPDiMwjKl8Mplq7Bd4ges2L5l1PqWl8vSoD
Ok, looks like you aren't passing the customer parameter when creating a Checkout Session
So I guess you're relying on Checkout to create the Customer for you?
I think so, I'm following this guide:
https://stripe.com/docs/billing/quickstart
Yep, perfect. So in this case the ID that you want to save to your database will from the customer field of the Checkout Session object
You can then map that Customer ID directly to the related user in your database I guess
Then it can be used to create the Customer Portal session when they're authenticated in your app/website
Ah, I see it. So the customer.id is generated each time the Checkout page is loaded -- if I do this, for example:
const session = await stripe.checkout.sessions.create({
...
});
//save session.id to customer record in database
and the customer cancels, it will just save a new session.id when they try to checkout again.
And then to create the customer portal session, I just pass that saved session.id through as the session_id form value?
and the customer cancels, it will just save a new session.id when they try to checkout again.
Well at that point you'll already have a Customer, so you can just pass thecustomerparameter when creating any subsequent Checkout Sessions. Otherwise you're going to end up with a ton of duplicated Customers. https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-customer
And then to create the customer portal session, I just pass that saved session.id through as the session_id form value?
You'd pass thecus_xxxID from thecustomerfield on the Session object (sosession.customer): https://stripe.com/docs/api/customer_portal/sessions/create#create_portal_session-customer
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Well at that point you'll already have a Customer
I'm a bit lost here, as far as I can see no Customer was created when I submit the form to/create-checkout-session
A session is created but no Customer was created that I can see on dashboard (hadn't paid yet)
It won't be, the Customer will be created on payment/completion of the Session
Recommendation would be to listen for the checkout.session.completed event and handle in a webhook: https://stripe.com/docs/payments/checkout/fulfill-orders
Ah got it, and then
const session = event.data.object;
session.id would be what I need to save here, right
My next question is how can I access the metadata from the webhooks? I've saved the mongodb customer userID when creating the session:
subscription_data: {
metadata: {
mongoID: userID
}
},
You'd pass the cus_xxx ID from the customer field on the Session object (so session.customer):
Sorry, I mean session.customer is what I should save?
And then in the form, I should pass it like this (Vue :dynamic value)?
<form action="https://australopithecus.xyz/api/create-portal-session" method="POST">
<input type="hidden" id="session-id" name="session_id" :value="customer" />
My next question is how can I access the metadata from the webhooks? I've saved the mongodb customer userID when creating the session
You'll likely need to listen for a different event for that:customer.subscription.created
And then in the form, I should pass it like this (Vue :dynamic value)?
Not overly familiar with Vue, but I guess it depends on what yourcreate-portal-sessionAPI/function looks like
Ok, understood
My function is the one from the guide:
app.post('/create-portal-session', async (req, res) => {
// For demonstration purposes, we're using the Checkout session to retrieve the customer ID.
// Typically this is stored alongside the authenticated user in your database.
const { session_id } = req.body;
const checkoutSession = await stripe.checkout.sessions.retrieve(session_id);
// This is the url to which the customer will be redirected when they are done
// managing their billing with the portal.
const returnUrl = YOUR_DOMAIN;
const portalSession = await stripe.billingPortal.sessions.create({
customer: checkoutSession.customer,
return_url: returnUrl,
});
res.redirect(303, portalSession.url);
});
You won't need the checkout.sessions.retrieve call
You can just pass your req.body.session_id (technically customer_id) directly to the Customer Portal call:
const portalSession = await stripe.billingPortal.sessions.create({
customer: req.body.session_id,
return_url: returnUrl,
});
Okay got it, thanks I'll test all of this now
Np!
Part of my hook for the checkout.session.completed event is:
case 'checkout.session.completed':
const session = event.data.object;
const subscription = await stripe.subscriptions.retrieve(
session.subscription
);
// subscription.metadata.mongoID //this is my customer database record ID metadata
This correctly retrieves the subscription, even though the checkout.session.completed' event occurs before the customer.subscription.created event. Is this to be expected?
We can't guarantee ordering of events, yeah
Is there any way I can ensure I get the metadata every time? If I wrap that in a loop while subscription == null maybe?
The subscription object should always exist at this time
Just the ordering of events might not reflect that
Okay, understood
If it's a concern, just use the customer.susbcription.created event
Generally you'd listen for Invoice related events, as opposed to the Payment Intent related events: https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=checkout#provision-and-monitor
There's a direct reference to the sub_xxx on the Invoice object
Ah okay, great, thank you!