#josephmalam-customer-portal

1 messages · Page 1 of 1 (latest)

ancient niche
#

Hey! What is 'session_id' in this instance? Are you using Checkout?

opaque atlas
#

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)

ancient niche
#

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

opaque atlas
ancient niche
#

Yep

opaque atlas
#

cs_test_a1131rMjAeKLN6h134iUGATLPDiMwjKl8Mplq7Bd4ges2L5l1PqWl8vSoD

ancient niche
#

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?

opaque atlas
ancient niche
#

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

opaque atlas
#

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?

ancient niche
#

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 the customer parameter 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 the cus_xxx ID from the customer field on the Session object (so session.customer): https://stripe.com/docs/api/customer_portal/sessions/create#create_portal_session-customer

opaque atlas
#

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)

ancient niche
#

It won't be, the Customer will be created on payment/completion of the Session

opaque atlas
#

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" />
ancient niche
#

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 your create-portal-session API/function looks like

opaque atlas
# ancient niche > And then in the form, I should pass it like this (Vue :dynamic value)? Not ove...

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);
});
ancient niche
#

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,
 });
opaque atlas
#

Okay got it, thanks I'll test all of this now

ancient niche
#

Np!

opaque atlas
# ancient niche > My next question is how can I access the metadata from the webhooks? I've save...

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?

ancient niche
#

We can't guarantee ordering of events, yeah

opaque atlas
#

Is there any way I can ensure I get the metadata every time? If I wrap that in a loop while subscription == null maybe?

ancient niche
#

The subscription object should always exist at this time

#

Just the ordering of events might not reflect that

opaque atlas
#

Okay, understood

ancient niche
#

If it's a concern, just use the customer.susbcription.created event

ancient niche
#

There's a direct reference to the sub_xxx on the Invoice object

opaque atlas
#

Ah okay, great, thank you!