#amanuel

1 messages · Page 1 of 1 (latest)

worn vergeBOT
slow flint
#

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?

lone orchid
#

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:

  1. List out all payment methods connected to the customer id
  2. Take the most recent one if available (index 0)
  3. 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

slow flint
#

it's fine to leave the incomplete PaymentIntents as they are.

#

i.e.

  1. list the existing PaymentMethods on the Customer
  2. if the Customer selects an existing PaymentMethod, use stripe.confirmCardPayment with the existing PaymentMethod id
lone orchid
#

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

slow flint
#

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

lone orchid
#

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

slow flint
#

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
lone orchid
#

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

slow flint
#

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

lone orchid
#

Ok, but stripe.confirmPayment expects an element

#

It is a required parameter

slow flint
#

stripe.confirmPayment and stripe.confirmCardPayment are two different functions

#

which one are you using?

lone orchid
#

I'm sorry, I totally did not read that correctly

#

Thank you so much, I'll try and see if it works now

slow flint
#

let me know if you're still having trouble!

lone orchid
#

Thank you, yeah I like this method much better, it feels safer than before.

#

Any suggestions on how to display credit cards to user?

slow flint
#

what are you looking for suggestions specifically? e.g. are you asking what card information can you display to the customers?

lone orchid
#

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

slow flint
#

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

lone orchid
#

How do I determine the name/photo though?

#

And thank you so much!

slow flint
#

you can't, not from the information Stripe returns

lone orchid
#

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?

slow flint
#

hmmm, no such future plans that i'm aware of

lone orchid
#

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

slow flint
#

will pass on the feedback 😄

lone orchid
#

Awesome! What product are you working for btw?

#

I have a friend at Stripe actually

slow flint
#

i'm not working on any specific product. I'm on a team that supports developers that use Stripe

lone orchid
#

That's great!

#

You've been wonderful!

lone orchid
#

@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?

slow flint
lone orchid
#

Thank you so much!

#

Also, is there a way to make the card the default payment when they first pay using PaymentElement?

slow flint
#

is it not currently? what's the default PaymentMethod that is showing?

lone orchid
#

I don't think so

#

Let me try to create a new customer and try

#

This is what I see

#

None of them default

slow flint
lone orchid
#

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?

keen sluice
#

Hi @lone orchid I'm taking over

lone orchid
#

For example when I do this:

    const { error } = await stripe.confirmPayment({
        elements,
                ...
    });
#

Hi @keen sluice Thank you so much

keen sluice
#

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?

lone orchid
#

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

keen sluice
#

OK. So you want the PaymentElement to show the existing attached payment_methods ? is this the correct understanding?

lone orchid
#

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.

keen sluice
#

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

lone orchid
#

Oh I see

#

So is this a viable solution?

#

How do I know what their default payment method is then

keen sluice
#

Alternatively you can integrate the Link Element, which can present list of saved payment methods for your customer to choose

lone orchid
#

Hm

keen sluice
lone orchid
#

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?

keen sluice
#

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.

lone orchid
#

Oh damn

keen sluice
#

Sure, you can get it from invoice_setting.default_payment_method or default_source

lone orchid
#

So to be clear, I have to actually set this myself though

keen sluice
#

Yes you are right, when creating a PaymentIntent with a existing payment_method, you need to explicilty specify a payment_method.

lone orchid
#
  1. Process their first payment (after stripe.confirmPayment())
  2. Grab the list of cards from customer (should only be 1, and index 0)
  3. Save that card as default_source

Next time they try to checkout:

  1. Fetch card from default_source
  2. Grab the list of cards from customer (and filter out the one we got in step 1. already)
#

Is this a viable solution?

keen sluice
#
  1. The stripe.confirmPayment() returns a payment_intent object which you can find the payment_method from it, there's no need to make another API call to grab the list of cards again
  2. You should save the payment_method to invoice_settings.default_payment_method, the default_source property is there for backward compatibility purpose.
lone orchid
#

Oh, perfect! Ok, I'll try that

keen sluice
#
  1. You don't need to use checkout or PaymentElement to charge a customer with a saved payment_method
lone orchid
#

Can you stay updated if I need more help after?

keen sluice
lone orchid
#

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

keen sluice
#

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.

lone orchid
#

Thanks!

#

Yeah I am not using PaymentElement here!

keen sluice
#

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.

lone orchid
#

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/",
        },
    });
keen sluice
#
    const { error, paymentIntent } = await stripe.confirmPayment({
...
lone orchid
#

Property 'paymentIntent' does not exist on type '{ error: StripeError; }'.

keen sluice
#

Was the paymentIntent confirmed succesfully?

lone orchid
#

This is in the editor

#

It isn't returning a PaymentIntent

keen sluice
#

What @stripe/stripe-js version are you using?

lone orchid
#

@stripe/stripe-js@1.44.1

keen sluice
#

I see, it seems like it's removed in the newer verison

lone orchid
#

Great! Is that the only way after doing confirmPayment()?

#

Thank you

keen sluice
#

Yes, you can call it after confirmPayment()

lone orchid
#

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

keen sluice
#

You have specified stripe in the useEffect dependency list, it tells React only to run the function if stripe changes.

lone orchid
#

So I thought when we submit the confirmPayment it changes stripe?

#

I've done it exactly how it is shown here

keen sluice
#

Did you use the downloaded example code from this page?

lone orchid
#

They're different?

#

Let me check!

#

@keen sluice The downloaded files are the exact same?

keen sluice
#

Hi @lone orchid thanks for waiting, can you download the example project and see if it works for you?

lone orchid
#

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?

keen sluice
#

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.

lone orchid
#

And there is no way to process what I want before confirmPayment

#

So my only option is after the redirect

keen sluice
lone orchid
#

But I do want redirect with the callback url attached?

keen sluice
#

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.

lone orchid
#

All right, thank you so much