#hans_code

1 messages ¡ Page 1 of 1 (latest)

wanton oracleBOT
#

👋 Welcome to your new thread!

⏲️ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

⏱️ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

🔗 This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1341917362978291793

📝 Have more to share? Add more details, code, screenshots, videos, etc. below.

thin condor
#

Hello! Yes, generally speaking you can collect payment info before creating the Customer.

lusty willow
#
      console.log({
        msg: 'about to invoke stripe.setupIntents.update',
        params: { setupIntentId: setupIntent.id, customerId: customer.id },
      });
      await stripe.setupIntents.update(setupIntent.id, {
        customer: customer.id,
      });
      console.log({ msg: 'completed stripe.setupIntents.update' });

results in

"Some of the parameters you provided (customer) cannot be used when modifying a SetupIntent that was created by Checkout. You can try again without those parameters.",
thin condor
#

You can create the Setup Intent without the customer property.

lusty willow
#
      const session = await stripe.checkout.sessions.create({
        mode: 'setup',
        payment_method_types: ['card'],
        success_url: 'http://localhost:3000/success?session_id={CHECKOUT_SESSION_ID}',
        cancel_url: 'http://localhost:3000/cancel',
        customer_email: CUSTOMER_EMAIL,
      });
thin condor
#

That's Checkout Session code which doesn't seem related to what you're trying to do?

#

Or, if it is, I need you to explain more about what you're trying to build, provide more context, etc.

lusty willow
#

Here's our flow
(1) stripe.checkout.sessions.create - to collect payment information
(2) stripe.setupIntents.retrieve(completedSession.setup_intent) - to confirm setup intent completed and get id
(3) stripe.customers.create - to create a new customer object
(4) stripe.setupIntents.update - to attach the setup intent to the customer (fails)

thin condor
#

Oh, okay, so there's a lot I need to explain about that, give me a bit to type this out across several messages...

#

First, if you're using Checkout Sessions to collect payment information, Checkout itself will create the Customer for you. You can't prevent that from happening, but it should only happen if Checkout is successful.

#

Actually, before I keep going, can you give me one of your Checkout Session IDs so I can take a look? I want to make sure I have full context on what you're doing.

lusty willow
#

yes, just a moment

#

cs_test_c1bbYl8elVqqX8UeXP5wX0t5C0D4xSgBbcDYn2ALd82w0SAZnd868OULy6

thin condor
#

Back to your flow as described, creating a Customer should be redundant because Checkout should have already created one and assocaited the Payment Method with them.

#

As far as the Setup Intent created by Checkout, that should also already be associated with the Customer Checkout created and doesn't need any further action on your part.

#

Looking at that Checkout Session now...

lusty willow
#

I do not want a customer created as part of creating a checkout session. We only want a customer to be created if payment is successfully collected. This is what we're trying to accomplish because of our tax integration.

thin condor
#

Hm, this Checkout Session didn't create a Customer, which isn't what I would have expected. I'm taking a closer look now. In the meantime, I want to clarify that Checkout won't create a Customer if one doesn't already exist and collecting the payment info fails, so it sounds like it should work the way you want, although I'm not sure why it's working the way it is in this specific example yet...

#

Ah, okay, what threw me off here is that I forgot we changed the default for customer_creation from always to if_required in an API version prior to the one you're using: https://docs.stripe.com/upgrades#2022-08-01

Okay, so it's expected that a Customer wasn't created here. There are two paths forward from this point:

  1. (Recommended) Try setting customer_creation to always when you create the Checkout Session. What should happen is, when the Checkout Session is successful, it should create the Customer for you and attach the Payment Method to them. If the Checkout Session isn't successful it shouldn't create a Customer. I believe that's the behavior you want.
  2. Keep the Checkout Session stuff as-is, and after you get the checkout.session.completed Event create a Customer, then attach the Payment Method from the Checkout Session to the Customer. There's no need (and, in fact, no way) to retroactively associate the Setup Intent with the Customer in this scenario.
lusty willow
#

I'm trying to follow #2 with the following code

      await stripe.setupIntents.update(setupIntent.id, {
        customer: customer.id,
      });
thin condor
#

Yeah, as I mentioned above, you can't do that.

#

That's not a thing at all. At no point during either option will you be updating the Setup Intent.

lusty willow
#

I don't know how to follow #2. We have completed the checkout session and completed, then created a customer, I don't know how to attach a payment method from what we have

thin condor
#

I linked directly to the API you need to use to attach the Payment Method from the Checkout Session to a Customer above. What questions do you have about that?

lusty willow
#

I'm not sure how to go from a setup intent to a payment method

thin condor
#

The Setup Intent has a payment_method property which points to the Payment Method.

#

To clarify the issue, is this code running when you receive a checkout.session.completed Event? If not, what's triggering this code to run?

#

If so, when you recieve the checkout.session.completed Event, the Checkout Session inside has a setup_intent property set to the ID of the Setup Intent. You can use that to retrieve the Setup Intent from the API and get the Payment Method ID from it.

lusty willow
#

for now, I'm writing a script called create-organization.mts that goes through the full flow. It will open a url to complete the checkout session and await me pressing enter for that session to be completed.

So, it's not being invoked by a webhook.

thin condor
#

Okay, so in the script where are you getting the Setup Intent ID from?

lusty willow
#

First, here's what I just updated to use paymentMethods attach instead of my prior setupIntents.update

console.log({
        msg: 'about to invoke stripe.paymentMethods.retrieve',
        params: { paymentMethodId: setupIntent.payment_method },
      });
      const paymentMethod = await stripe.paymentMethods.retrieve(setupIntent.payment_method as string);
      console.log({ msg: 'completed stripe.paymentMethods.retrieve', result: { type: paymentMethod.type } });

      console.log({
        msg: 'about to invoke stripe.paymentMethods.attach',
        params: { paymentMethodId: paymentMethod.id, customerId: customer.id },
      });
      await stripe.paymentMethods.attach(paymentMethod.id, {
        customer: customer.id,
      });
      console.log({ msg: 'completed stripe.paymentMethods.attach' });
#

Here is where we've created a checkout session, and then once prompted (pressing enter) using that session id to get the setup intent

      console.log({ msg: 'about to invoke stripe.checkout.sessions.retrieve', params: { sessionId: session.id } });
      completedSession = await stripe.checkout.sessions.retrieve(session.id);
      console.log({ msg: 'completed stripe.checkout.sessions.retrieve', result: { status: completedSession.status } });


    console.log({
      msg: 'about to invoke stripe.setupIntents.retrieve',
      params: { setupIntentId: completedSession.setup_intent },
    });
    const setupIntent = await stripe.setupIntents.retrieve(completedSession.setup_intent as string);
    console.log({ msg: 'completed stripe.setupIntents.retrieve', result: { status: setupIntent.status } });

thin condor
#

I can't review your code or tell you what will happen when it runs, but I'm happy to answer specific questions if you're stuck on something.

lusty willow
#

with the update, the script has completed

#

I'm checking out the setup. It's also creating WorkOS and Orb objects along with Stripe and linking them all together.

#

I think this is now working for our use case. I really appreciate the patience and redirect for setupIntent to paymentMethod