#rohailkamran

1 messages ยท Page 1 of 1 (latest)

drifting baneBOT
#

Hello! We'll be with you shortly. Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.

slate plinth
#

hi there!

#

what's your quesiton?

boreal grotto
#

Hi!

#

So Soma yesterday you sent me this link to follow through for customer creation and payments/charges:

https://stripe.com/docs/payments/save-and-reuse?platform=web&ui=checkout

I am about 4/5 of the way there.

I have set up an endpoint at '/api/create-checkout' that does the following:

exports.createCheckoutSession = async (req, res) => {
    console.log("request recieved to create session");
    try {
        const session = await stripe.checkout.sessions.create({
            mode: 'setup',
            currency: 'usd',
            customer: req.customer_id,
            success_url: 'http://localhost:3001/success',
            cancel_url: 'http://localhost:3001/cancel',
          });
          
          const setupIntent = await stripe.setupIntents.retrieve(session.data.object.setup_intent);

          res.json(setupIntent);
    } catch (error) {
        res.json(error);
    }

The problem is that I am receiving {} in response.

If I remove the setup_intent part and just return the session, I do get a valid response. How do I move from here?

Learn how to save payment details and charge your customers later.

#

I have hooks set up as well to listen to checkout.session.completed that I have tested to be working through stripe cli

slate plinth
#

wait, why are you creating a SetupIntent?

#

you don't need one

#

just create the Checkout Session and nothing else

#

and return the session.url and redirect the user there.

boreal grotto
#

hmmm I see... do you remember my exact use case? Should I re-open the ticket from yesterday?

slate plinth
#

yes, and I remember mentionning you can either use SetupIntent or Checkout Session. Not both at the same time.

boreal grotto
#

rightt

#

ohh lolol

#

okay... so if I return session.url

#

hmmm

#

I think I am missing something here. Give me a sec to type out exactly what I am doing here.

drifting baneBOT
boreal grotto
#

Step 1: Creating a customer (DONE)

const customer = await stripe.customers.create({
          name: fullName,
          email: email,
        });

Step 2: Attaching a payment method to the customer (DONE)

const checkoutSession = await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      mode: "setup",
      customer: customer.id,
      success_url: `<what-should-I-put-here-on-localhost>`,
      cancel_url: `<what-should-I-put-here-on-localhost>`
    });

Step 3: (NOT DONE)
redirect the user to the Checkout Session URL

Step 4: Getting payment methods for customer when they buy a product: (PENDING)

const paymentMethods = await stripe.paymentMethods.list({
  customer: '{{CUSTOMER_ID}}',
  type: 'card',
});

Step 5: Charge a payment from one of their payment methods: (PENDING)

const paymentIntent = await stripe.paymentIntents.create({
  amount: 2000,
  currency: 'usd',
  confirm:true,
  customer: customerId,
  payment_method: paymentMethods[0].id,
  return_url:'http://localhost:3001/paid
});
slate plinth
#

yep that's correct

boreal grotto
#

Great. I have a couple of confusions regarding this

#

Q1: In step 2, I am literally doing:

payment_method_types:["card"]

Should I instead put an actual card number or something?

#

Question 2 depends on answer to question 1

normal mica
#

No, the card details are collected from the customer when you redirect them to the Checkout Session page

#

You use the payment_method_types parameter tp specify the types of PMs, like card, you want your customers to be able to use

boreal grotto
#

I see I see.

#

So the url I return in step 3 should be a stripe hosted url, correct?

normal mica
#

Yes, it'll be in the response payload from your request in step 2. checkoutSession.url

boreal grotto
#

Great!

So when the user is on the stripe hosted page, the page where the user will enter their payment info and click "Pay" or something I am assuming, what happens after they click pay?

Where would my server and client come back into play?

#

In other words, when and how do I get to perform steps 4 and 5?

normal mica
#

You'd likely setup webhooks to be notified of the successful Checkout Session to save the card (checkout.session.completed events) andn then you can action that accordingly

boreal grotto
#

I see! This sounds good. Because I have hooks set up to listen for that event, I was worried why they were not being triggered. Now I know.

So the checkout.session.completed event will get triggered from the stripe hosted checkout page.

Once the event is triggered, I have to do as follows (correct me if I am wrong):

.
.
.
if(event.type == "checkout.session.completed"){

//step 4
  const paymentMethods = await stripe.paymentMethods.list({
  customer: '{{CUSTOMER_ID}}',
  type: 'card',
});

//step 5
const paymentIntent = await stripe.paymentIntents.create({
  amount: 2000,
  currency: 'usd',
  confirm:true,
  customer: customerId,
  payment_method: paymentMethods[0].id,
  return_url:'http://localhost:3001/paid
});

}
normal mica
#

Yes, you can get the cus_xxx from the event too

boreal grotto
#

I should have the customer_id, amount, currency in the event right?

#

what should I return as a response after step 5 is done? Like standard approach

normal mica
#

No there wouldn't be an amount or currency as your setup session doesn't involve a payment

boreal grotto
#

hmmm what would be the easiest way for me to have access to amount and currency in step 5? Because when I receive the event, I won't know what product the checkout session event was triggered for...

normal mica
#

There 'd be no amount or currency in a mode: 'setup' session. It simply collect payment information โ€“ there's no payment

#

You'd need to provide those values for the payment you want to create

boreal grotto
#

I see, is there any mode that would allow me to do both?

normal mica
boreal grotto
#

hmmm

#

I see.

#

Thanks for this. I just completed step 1,2,3 and I have code in place for steps 4 and 5 as well.

#

As soon as I fill info on the stripe hosted page and click save, I am redirected to the success url.

However, my hook does not hear the event being triggered....

Is it because I am on localhost and that is not publicly accessible to stripe for events?

normal mica
boreal grotto
#

Thanks! I was able to complete the stripe customer creation flow. Now I am heading on to payment. Thanks!!

normal mica
boreal grotto
# normal mica You'd use `mode: 'payment'` and pass `setup_future_usage: 'off_session'` paramet...

So you are saying that I can potentially accomplish both

a. customer creation
b. payment completion

only by changing step 2 from:

const checkoutSession = await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      mode: "setup",
      customer: customer.id,
      success_url: `<what-should-I-put-here-on-localhost>`,
      cancel_url: `<what-should-I-put-here-on-localhost>`
    });

to:

const checkoutSession = await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      mode: "payment",
      customer: customer.id,
      success_url: `<what-should-I-put-here-on-localhost>`,
      cancel_url: `<what-should-I-put-here-on-localhost>`,
      pass setup_future_usage: 'off_session'
    });
normal mica
#

Well, yes, but the parameters are wrong:

await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      mode: "payment",
      success_url: `<what-should-I-put-here-on-localhost>`,
      cancel_url: `<what-should-I-put-here-on-localhost>`,
      payment_intent_data: {
        setup_future_usage: 'off_session'
      }
    });
boreal grotto
normal mica
#

When passing setup_future_usage Checkout will automatically create the customer for you

drifting baneBOT
boreal grotto
normal mica
#

Yes exactly

boreal grotto
#

Sounds really neat. Thanks

#

Shouldn't I be able to tell the amount here?

await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      mode: "payment",
      success_url: `<what-should-I-put-here-on-localhost>`,
      cancel_url: `<what-should-I-put-here-on-localhost>`,
      payment_intent_data: {
        setup_future_usage: 'off_session'
      }
    });
rose goblet
#

๐Ÿ‘‹ taking over for my colleague. Let me catch up.

boreal grotto
#

Aoa hey! ๐Ÿ‘‹
Sure

rose goblet
#

yes you need to pass in the line_items param

boreal grotto
#

I see...

so:

await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      mode: "payment",
      success_url: `<what-should-I-put-here-on-localhost>`,
      cancel_url: `<what-should-I-put-here-on-localhost>`,
      payment_intent_data: {
        setup_future_usage: 'off_session'
      }
  line_items: [
    {
      price: '{{PRICE_ID}}',
      quantity: 1,
    },
  ],
    });

#

Oh lol wait lemme see

#

yeah

#

but now new question lolol

rose goblet
#

sure

boreal grotto
#

how do I get/know a price id?

#

Can't I simply pass in an amount?

rose goblet
#

but you can also manage your products and prices in Stripe either through the dashboard or via the API

boreal grotto
#

So correct me if I am wrong but this would mean:

await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      mode: "payment",
      success_url: `<what-should-I-put-here-on-localhost>`,
      cancel_url: `<what-should-I-put-here-on-localhost>`,
      payment_intent_data: {
        setup_future_usage: 'off_session'
      }
  line_items: [
    {
      price_data:{
          unit_amount:10,
          currency: "usd"
      },
      quantity: 10,
    },
  ],
    });

Which according to my understanding should result in:

a. customer being created IF they don't exist
b. payment of $100 being made

#

Will this work? Or is price_id compulsory?

rose goblet
#

you would also need to pass in either a Product ID or a product_data hash within the price_data

#

the unit_amount is in cents

#

so you're passing 10* 0.10 which is only 1$

boreal grotto
#
      payment_method_types: ["card"],
      mode: "payment",
      success_url: `<what-should-I-put-here-on-localhost>`,
      cancel_url: `<what-should-I-put-here-on-localhost>`,
      payment_intent_data: {
        setup_future_usage: 'off_session'
      }
  line_items: [
    {
      price_data:{
          product_id:<xyzid_generated_by_stripe>,
          unit_amount:1000,
          currency: "usd"
      },
      quantity: 10,
    },
  ],
    });
#

So this should result in:

๐ŸŸก customer creation if customer does not exist
๐ŸŸก payment of 100$

right?

#

This eliminates the need for a price_id, right?

rose goblet
#

sorry it's been a bit busy on discord

#

I'm back

#

that wouldn't create a customer though

#

if you want to automatically create a new customer each time

boreal grotto
#

I see, so this would become:

await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      mode: "payment",
      
      success_url: `<what-should-I-put-here-on-localhost>`,
      cancel_url: `<what-should-I-put-here-on-localhost>`,
      payment_intent_data: {
        setup_future_usage: 'off_session'
      },
      customer_creation: 'always',
  line_items: [
    {
      price_data:{
          product_id:<xyzid_generated_by_stripe>,
          unit_amount:1000,
          currency: "usd"
      },
      quantity: 10,
    },
  ],
    });
#

Right?

rose goblet
#

yes if you already created a Product

#

wait, it's product not product_id

#

the name of the param

boreal grotto
#

Oh okayy

rose goblet
#

@boreal grotto please look at the API references we share to you

#

you have all of the different properties there

boreal grotto
#

Right lol sorry I missed that

rose goblet
#

so you either use product if you already created a Product or product_data if you want to generate one inline

boreal grotto
#

Right, I am currently going to hard code the id of a product that I have created.

#

as

#

product: product_id

rose goblet
#

ok

boreal grotto
#

Thanks for all the help you guys. This is awesome.

rose goblet
#

sure thing let me know if you need any more help