#amanuel
1 messages · Page 1 of 1 (latest)
hello! you don't necessarily need to do anything about those PaymentIntents. Can you share more context about why you're concerned about those additional PaymentIntents?
I'm not concerned, it just occurred to me while testing that I have a long list of payment_intents and I was wondering if I need to handle them or if it is a security concern that they're just there
So it is just fine to leave them as it is?
Thank you so much for responding so quickly.
@slow flint I am currently implementing a way to let a customer pay for something without having to type in their card details again:
On server side I do this:
- List out all payment methods connected to the customer id
- Take the most recent one if available (index 0)
- Inject the id that comes from step 2 into a paymentIntent with parameter confirm.
From client side: I use fetch to trigger this endpoint and it shows up on my stripe dashboard
Is this actually how to implement it? I didn't find great documentation on this part. In the future, I also want to show the customer all saved cards that they can select between instead of just clicking on a button that charges them immediately
it's fine to leave the incomplete PaymentIntents as they are.
If the customer is already on your site, then you can use stripe.confirmCardPayment with the existing PaymentMethod id - https://stripe.com/docs/js/payment_intents/confirm_card_payment#stripe_confirm_card_payment-data-payment_method
i.e.
- list the existing PaymentMethods on the Customer
- if the Customer selects an existing PaymentMethod, use
stripe.confirmCardPaymentwith the existing PaymentMethod id
Awesome, so this is if I want to give them the option of what cards?
What about the process I explained above? I simply have a "Pay now" button, and if you click it, it will automatically fetch their most recent payment method, and it will pay for them. Like this:
const paymentMethods = await stripe.paymentMethods.list({
customer: customerId,
type: "card",
});
const paymentIntent = await stripe.paymentIntents.create({
customer: customerId,
setup_future_usage: "on_session",
amount: 5000,
currency: "usd",
payment_method: paymentMethods.data[0].id,
payment_method_types: ["card"],
confirm: true,
);
So you do need to use the Card Element here?
I am using the PaymentElement for first time insert of the card details. What Element should I use afterwards?
Next time they checkout, I want their card to be available there and let them select it before clicking purchase
no, you don't need to use the Card Element in the code you just pasted.
I am using the PaymentElement for first time insert of the card details. What Element should I use afterwards?
I'm a bit confused as to what you mean by afterwards
Ok so imagine you go to purchase something, the first time you will see the PaymentElement form. You type in all your details and purchase.
Consequently, you want to make more purchases. I want my customers to be able to make purchases one-click if that makes sense
If they press on something, it will show them the price, their saved cards and a "pay now" button
Here is an example from Amazon:
Thank you so much for your responses btw, I really appreciate it
I have been a bit stuck on this part
To clarify, if you want to have a "Pay now" button, and if you click it, it will automatically fetch the most recent payment method and make payment, what you have will work.
Alternatively, you can use stripe.confirmCardPayment to confirm the corresponding PaymentIntent with the existing PaymentMethod on your frontend instead.
If you want the card to be available on your site to let the customer select before clicking purchase, then you need to implement all of these yourself i.e.
- retrieving the list of PaymentMethods for the customer, displaying it for selection
- after the customer makes a selection, then create and confirm the PaymentIntent
That answers my question, awesome!
So I will just skip using PaymentElement for this
I thought there was something I could use it for listing out the cards or something
The only thing though, is if I have a stripe.confirmCardPayment, where would I implement this?
Client side or server? If I try to use const stripe = useStrip() without the Element, it is complaining
ah, no, we don't have any component to help you list all the cards out on your site.
stripe.confirmCardPayment should be on your client
stripe.confirmPayment and stripe.confirmCardPayment are two different functions
which one are you using?
I'm sorry, I totally did not read that correctly
Thank you so much, I'll try and see if it works now
let me know if you're still having trouble!
Thank you, yeah I like this method much better, it feels safer than before.
Any suggestions on how to display credit cards to user?
what are you looking for suggestions specifically? e.g. are you asking what card information can you display to the customers?
Yeah exactly, and what information do I have access to?
Do I have access to this?
and perhaps the expiration date?
Photo of credit card, name of credit card, ending of credit card, expires on
the information that you can access on a PaymentMethod (card) object is listed here : https://stripe.com/docs/api/payment_methods/object#payment_method_object-card
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
you won't have a photo, nor the name of the cc. You can get the last4 and expiry
at the bare minimum, you should display the last4 of the card. Anything else that you want to display from the information returned is really up to you
you can't, not from the information Stripe returns
damn
All right, I'll resort to cc type then
just show them [visa]/[mastercard] etc
Thank you so much though
Is this something that will be supported in the future perhaps?
hmmm, no such future plans that i'm aware of
If there is a way I can contribute in the future, let me know! This feature is highly requested in ecommerce and just in general
Just like how Amazon has it above
will pass on the feedback 😄
i'm not working on any specific product. I'm on a team that supports developers that use Stripe
@slow flint Also, I forgot to ask about this:
Along with the buy-now button, is there a way to also display just google-pay/apple-pay on the side?
you would implement the payment request button : https://stripe.com/docs/stripe-js/elements/payment-request-button
Thank you so much!
Also, is there a way to make the card the default payment when they first pay using PaymentElement?
is it not currently? what's the default PaymentMethod that is showing?
I don't think so
Let me try to create a new customer and try
This is what I see
None of them default
ah, i misunderstood the question. Anyway, to make a PaymentMethod the default payment method on the customer, you would need to set the PaymentMethod id in invoice_settings.default_payment_method [0] on the customer
[0] https://stripe.com/docs/api/customers/update#update_customer-invoice_settings-default_payment_method
I don't follow
So right now, I have a PaymentElement
They type in their credit card and hit pay
Is there a way to make that card immediately the default?
Hi @lone orchid I'm taking over
For example when I do this:
const { error } = await stripe.confirmPayment({
elements,
...
});
Hi @keen sluice Thank you so much
Is there a way to make that card immediately the default? -> so you want to set a default payment_method to your customer so that you don't need to specify one when making a future charges?
Ok
So I have this
It will show up for a new customer
But once they go through this, I want them to have that card as their default automatically
since it is their first card
OK. So you want the PaymentElement to show the existing attached payment_methods ? is this the correct understanding?
Right now, it is adding the card in their profile, but not as default card
No
I want the card they use in this form to be saved as their default payment card
Right now, I have a flow that you can checkout with one-click, and it basically goes and iterates through all their cards and selects the one at index 0
I don't want to do that
I want to be able to just save the card they first use as default, so that next time I can just reference their default card
Sorry if it is incoherent, let me know and I can try to explain better.
OK, this is not something that PaymentElement supports this moment, and customer object doesn't have a field for default payment_method.
The workaround is to save the desired payment_method ID to the customer's metadata, and you also need to build your own UI to present the default payment_method
Oh I see
So is this a viable solution?
How do I know what their default payment method is then
Alternatively you can integrate the Link Element, which can present list of saved payment methods for your customer to choose
Hm
Again, there's no concept of default_payment_method in a customer object in API level, you are free to decide which one of the attached payment methods, and use it as a default payment_method,
But it's right here in Dashboard
Oh, API level?
So if the customer wants to use this card out of 4 cards in total
Do I have to store this data myself?
Stripe is clearly saving this data for me, how come I can't get this?
This is default method shown in the Dashboard reflect either the invoice_setting.default_payment_method or default_source, which is the default payment method for invoices and subscriptions.
Oh damn
Sure, you can get it from invoice_setting.default_payment_method or default_source
So to be clear, I have to actually set this myself though
Yes you are right, when creating a PaymentIntent with a existing payment_method, you need to explicilty specify a payment_method.
- Process their first payment (after stripe.confirmPayment())
- Grab the list of cards from customer (should only be 1, and index 0)
- Save that card as default_source
Next time they try to checkout:
- Fetch card from default_source
- Grab the list of cards from customer (and filter out the one we got in step 1. already)
Is this a viable solution?
- The
stripe.confirmPayment()returns apayment_intentobject which you can find thepayment_methodfrom it, there's no need to make another API call to grab the list of cards again - You should save the
payment_methodtoinvoice_settings.default_payment_method, thedefault_sourceproperty is there for backward compatibility purpose.
Oh, perfect! Ok, I'll try that
- You don't need to use checkout or PaymentElement to charge a customer with a saved payment_method
Can you stay updated if I need more help after?
You should make an off-session charge directly from your server, see details in https://stripe.com/docs/payments/save-and-reuse?platform=web#charge-saved-payment-method.
Yeah that's what I am doing!
This is what I have right now:
const paymentMethods = await stripe.paymentMethods.list({
customer: customerId,
type: "card",
});
const paymentIntent = await stripe.paymentIntents.create({
customer: customerId,
setup_future_usage: "on_session",
amount: 5000,
currency: "usd",
payment_method: paymentMethods.data[0].id,
payment_method_types: ["card"],
});
if (paymentIntent && paymentIntent.client_secret) {
return {
succeeded: true,
clientSecret: paymentIntent.client_secret,
paymentMethods: paymentMethods.data,
};
}
Then I grab that clientSecret on the client and I call this when they press the buy now button:
const { error } = await stripe.confirmCardPayment(clientSecret);
So in that first part on the server, I want to be able to specify their default card, and also give them the option of any of their other cards if they want
but the primary intent should be using their default card
Since you have already specify a payment_method when creating a PaymentIntent, you can just do a off_session charge directly from your server without the need of using PaymentElement in frontend. I'd suggest you to go through the doc that I sent earlier.
Great, you can also set confirm:true to create and confirm a PaymentIntent at the same time. If the PaymentIntent status is requires_action, it means that a 3DS is needed for this payment. You should return the client_secret to frontend and call stripe.confirmCardPayment to initiate the 3DS flow.
Yeah I know!
I am purposefully not doing confirm:true
I don't want to directly initiate the payment
I want to allow the customer the option to see what card will be charged, and possibly change their payment method
If that makes sense
If I were to just do confirm:true, then if they press buy now, that's it the charge is done
Thank you so much though
I will implement the invoice_settings.default_payment_method
Thanks for letting me know that the confirmPayment returns a payment_intent
how do I get that payment_intent though?
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url:
process.env.NODE_ENV === "production"
? "https://example.com"
: "http://localhost:3000/",
},
});
const { error, paymentIntent } = await stripe.confirmPayment({
...
Property 'paymentIntent' does not exist on type '{ error: StripeError; }'.
Was the paymentIntent confirmed succesfully?
What @stripe/stripe-js version are you using?
@stripe/stripe-js@1.44.1
I see, it seems like it's removed in the newer verison
Alternatively you can call stripe.retrievePaymentIntent() to retrieve the PaymentIntent (https://stripe.com/docs/js/payment_intents/retrieve_payment_intent#stripe_retrieve_payment_intent) and get the payment_method.
Yes, you can call it after confirmPayment()
Hi @keen sluice I need some quick help!
After this runs:
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url:
process.env.NODE_ENV === "production"
? "https://example.com"
: "http://localhost:3000/",
},
});
I am expecting this to run:
useEffect(() => {
console.log("hello");
if (!stripe) {
return;
}
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);
if (!clientSecret) {
return;
}
stripe.retrievePaymentIntent(clientSecret).then(({ paymentIntent }) => {
if (!paymentIntent) return;
saveDefaultPaymentMethod({
stripeCustomerId: stripeCustomerId,
paymentMethodId: paymentIntent.payment_method as string,
});
switch (paymentIntent.status) {
case "succeeded":
setMessage("Payment succeeded!");
break;
case "processing":
setMessage("Your payment is processing.");
break;
case "requires_payment_method":
setMessage("Your payment was not successful, please try again.");
break;
default:
setMessage("Something went wrong.");
break;
}
});
}, [stripe]);
Within the same component
But it's not for some reason
It takes me back to the correct URL and it has the correct parameters in the URL, but I though this useEffect would be triggered, it seems like it is not
Any ideas here?
Here I am retrieving the intent like you said and then using that to get the payment method, I then have a method that does the stripe.customers.update() endpoint from the backend
You have specified stripe in the useEffect dependency list, it tells React only to run the function if stripe changes.
I'm using this example:
https://stripe.com/docs/payments/quickstart
So I thought when we submit the confirmPayment it changes stripe?
I've done it exactly how it is shown here
Did you use the downloaded example code from this page?
They're different?
Let me check!
@keen sluice The downloaded files are the exact same?
Hi @lone orchid thanks for waiting, can you download the example project and see if it works for you?
You want me to download the entire project?
I just need to look at the CheckoutForm.jsx
In the docs it says that
stripe.confirmPayment will return a Promise. Upon a successful confirmation, your user will be redirected to the return_url you provide before the Promise ever resolves.
So that useEffect won't have a chance to get triggered even because we'll be on a different url
It doesn't work
I see, the reason it doesn't actually work is because the example doesn't redirect anywhere, it just goes to the same page and that's why the useEffect is being triggered
What should I do here?
You don't need to rely on the page redirect to get the clientSecret, you can just pass the clientSecret from the parent Element to CheckoutForm as a prop.
I'm going back to the / directory though
And there is no way to process what I want before confirmPayment
So my only option is after the redirect
You can set redirect to if_required (https://stripe.com/docs/js/payment_intents/confirm_payment#confirm_payment_intent-options-redirect), so redirect will not happen for payment methods such as card.
But I do want redirect with the callback url attached?
This is going to require a bit more investigation. Sorry to redirect you, but can you write in to https://support.stripe.com/contact/email with your complete source code. We'll respond via email/ticket after looking into it further.
Find help and support for Stripe. Our support center provides answers on all types of situations, including account information, charges and refunds, and subscriptions information. Get your questions answered and find international support for Stripe.
All right, thank you so much