Reputation: 337
I use stripe payment element in client side. It sends a request to the server to retrieve the payment intent ID and the client secret.
I would like to be able to save the customer's payment method only if the customer has checked the box save this payment method for future purchases
But I would like the method to register only after I pass my complete flow in server side and be successful.
1- For this I set the capture method to "manual" when I create the payment intent and I capture and update the payment intent when all the server-side instructions have succeeded like this :
if (isWantSaveMethod) {
await stripe.paymentIntents.update(paymentIntent.id, { setup_future_usage: 'off_session' })
}
await stripe.paymentIntents.capture(paymentIntent.id)
=> The problem is that if I update the payment intent before it is captured, I get the error: You cannot provide a new payment method to a PaymentIntent when it has a status of requires_capture. You should either capture the remaining funds, or cancel this PaymentIntent and try again with a new PaymentIntent.
2- Then I tried to use an intent setup, which apparently allows us to link a payment method to a customer
if (isWantSaveMethod) {
await stripe.setupIntents.create({
payment_method: paymentIntent.payment_method,
confirm: true,
customer: paymentIntent.customer,
})
}
await stripe.paymentIntents.capture(paymentIntent.id)
=> But : The provided PaymentMethod was previously used with a PaymentIntent without Customer attachment, shared with a connected account without Customer attachment, or was detached from a Customer. It may not be used again. To use a PaymentMethod multiple times, you must attach it to a Customer first.
3- Then I tried to attach the payment intent to a customer like this :
if (isWantSaveMethod) {
await stripe.paymentMethods.attach(paymentIntent.payment_method, {
customer: paymentIntent.customer,
})
await stripe.setupIntents.create({
payment_method: paymentIntent.payment_method,
confirm: true,
customer: paymentIntent.customer,
})
}
await stripe.paymentIntents.capture(paymentIntent.id)
=> But I remember that the documentation say : To attach a new PaymentMethod to a customer for future payments, we recommend you use a SetupIntent or a PaymentIntent with setup_future_usage. These approaches will perform any necessary steps to ensure that the PaymentMethod can be used in a future payment.
So finally I'm here to know what's the good way to do that ? How popular websites do this thing ?
I just want to make sure that all my instructions in the server side executed successfully before save the payment method and I want to be able to use this method later
How can I do that while respecting the recommendations that stripe gave in relation to the method attachment ?
Upvotes: 1
Views: 3079
Reputation: 2163
When using Payment Element the intended user flow is that you would pass in setup_future_usage
when the Payment Intent is created. Stripe wants to know if you intend to use setup_future_usage
ahead of time so they can choose which Payment Method types to in the Payment Element (since not all of them can be used with setup_future_usage
. You should either change your checkout flow to ask whether your customer wants to save their payment method before showing the Payment Element, or you can use the individual elements like Card element instead (each of theses elements should support passing in setup_future_usage
with the client-side confirmation call - example here).
Alternatively (I really wouldn't recommend this), you can look into doing the following:
setup_future_usage
(you can find the list here).setup_future_usage
, and wait for the response to be successful before continuing to call confirmPayment
client-side.Upvotes: 2