0
votes

I'm using expressjs with sapper/svelte on the front.

I'm attempting to use stripe SetupIntent api and stripe.confirmCardSetup to save card details and attach it to a customer for future charges. I believe after reading the documentation I understand the flow of the process and my code is based on their example from the custom payment flow section

After submitting the credit card form, I get nothing. No card attached to the customer, no console log output and no errors in my application. The setupIntent is successfulLY created and I'm able to view it in my stripe dashboard but no card (paymentMethod) is created and attached to the customer. Here is my steps:

1- When a user create an account, I create a customer in stripe and
save the stripe customer's id in my db 
2- I use that stripe customerid to create a setupIntent on the server

const intent = stripe.setupIntents.create({
        customer: customer
    }).then(intent => {
        return res.end(JSON.stringify({ info: intent.client_secret }));
    });

At this stage, I need the client_secret to use it on the front with my card-element to submit the card details securely to stripe.
I confirm the setupIntent is indeed in my stripe dashboard. So this part is fine.

Now to the front part of my code :

I get the client_secret on the front of my application and use stripe.js to collect and submit the card details to be attached as a paymentMethod to the customer (which the client_secret has the customer.id), so the code is :

 let clientsecret
  let stripe = null
  let cardelement = null



    stripe = await loadStripe('pk_test_mykeys');
    var elements = await stripe.elements();
  cardelement = await elements.create('card');

  cardelement.on('ready', ()=>{});

  cardelement.on('change', ({error}) => {
  const displayError = document.getElementById('card-errors');
  if (error) {
  displayError.textContent = error.message;
  } else {
  displayError.textContent = '';
  }
  });  //end of card.on fn

  cardelement.mount("#card-element");

  return{
  stripe : stripe,
  cardelement : cardelement

  }

 
  function clickhandle(){

      stripe = stripe
    stripe.confirmCardSetup( csec , {
  payment_method: {
  card: cardelement,
  billing_details: { user : "testing setupIntent"
  }
  },
  setup_future_usage :  'on_session'
  })
  .then(function(result) {
  if (result.error) {
  console.log("there is an error")
  }
  if(result.setupIntent){
  console.log("here is the setupintent success result")
  }
  }); 

  }

Stripe.js works because I tested a paymentIntent and charging credit card on a different part of the application and the executed charges are showing in the stripe dashboard, so it is not the stripe.js script.

Is my process flow correct? Use stripe customer id to create setupIntent on my server and on the front the above code which collects card details and submit it using stripe.confirmCardSetup which will attach the paymentMethod/card details to the customer from the setupIntent client_secret?

Any help would be appreciated as I read the documentation and it is clear and straightforward. I followed it step by step. What am I missing?

2

2 Answers

1
votes

The correct process is described here: https://stripe.com/docs/payments/save-and-reuse#web-create-setup-intent and you're doing things a bit different that may be causing some issues.

I suspect that your inclusion of future_usage - which isn't actually a parameter to that function call - is likely the problem.

0
votes

After reading @floatingLomas comments, I went back and read carefully the documentation again. Here are the issues that need to be clear:

1- the form where you will mount the #card-elements needs to include the client_secret, whether in a hidden field or using data- attribute. read here if you don't know about it

So --note the data-secret attribute --my form code now is :

 <form data-secret={customersecret} on:submit={stripehandle} id="payment-form">
   
  <label for="card-element">Enter Your Credit Card Details:</label>
  <div id="card-element"></div>
  <div id="card-errors" role="alert"></div>
  <button id="submit">Pay -svelte2 component</button>

</form>

2- remove future_usage as @floatingLomas suggested. The correct parameter is "Usage" : "on_session" because the future_usage is for the paymentMethod api not the setupIntent api

3- The parameter billing_details: { "user" : "testing setupIntent" } was wrong. The api has parameter for name, phone, address but not user ;)

So the confirmCardSetup() code is the following:

 stripe.confirmCardSetup( csec , {
  payment_method: {
  card: cardelement,
  billing_details: { "name" : "testing setupIntent" }
  }
  })
  .then(function(result) {
   console.log("result :", result)
  
  })