#JeremyFlight

1 messages ยท Page 1 of 1 (latest)

thorn wraithBOT
timid grove
#

๐Ÿ‘‹ Thanks for reaching out
After creating the customer, you don't need to create manually the PaymentMethod and create a SetupIntent after. You should instead create a SetupIntent for the customer, and after confirming it, an authenticated PaymentMethod will be created and attached to the customer.
I suggest you to take a look at this complete guide for it.
https://stripe.com/docs/payments/save-and-reuse?platform=web#charge-saved-payment-method
For the 3DS popup, I suggest you also to let Stripe SDK handle it. When following that guide, you'll need to call stripe.confirmSetup which will handle and complete any required options, such as 3DS:
https://stripe.com/docs/js/setup_intents/confirm_setup

night knoll
#

But we're not using the Stripe JS library at all. We collect the card details from the customer and process those via your PHP SDK. If I have to use the Stripe JS SDK instead, I have a lot of code re-writing to do!

flint trellis
night knoll
#

No. We don't store the credit card details anywhere: just collect them from an HTML form and pass them through to Stripe via your SDK / API

flint trellis
#

that's still API Direct and requires a SAQ D since your server side code touches raw card details so it needs to be developed in a PCI compliant way to protect against accidental/deliberate leaks etc. I'd suggest consulting your legal advice

#

taking a step back, it's almost always wrong to create SetupIntent and the immeidately create a PaymentIntent. You only use SetupIntents if you're saving a card now without charging, and will charge it some hours/days/weeks later

night knoll
#

So if we swap to using the Stripe JS code, we can circumvent the PCI requirements?

flint trellis
night knoll
#

We don't immediately create a payment intent after a setup intent. That may be how it looks in the test script ๐Ÿ™‚ But we create the setup intent and then some while later (e.g. days or weeks) we create a payment intent to process a transaction

flint trellis
#

cool

#

so you want to simulate that later payment getting an exemption from 3D Secure?

night knoll
#

Yep

flint trellis
night knoll
#

Yep - doing all of that already! Stil get status of "requires_action" back from the PaymentIntent, despite having complete the 3DS verification process

flint trellis
#

do you have an example PaymentIntent ID pi_xxx?

flint trellis
#

bump @night knoll

night knoll
#

Try: pi_3LzjDVBZ9qUe1kQ51BBG3TXv

flint trellis
#

that PaymentIntent is not at all like the example at (b)

#

it's not passing off_session:true

#

compare with

#

note that setup_future_usage:off_session is not the same thing as off_session:true and they're not interchangeable, to be clear

night knoll
#

So at the moment, I pass this to my Setup Intent:

$arrData = array('usage' => 'off_session'
                ,'return_url' => 'https://XXX'
                ,'payment_method' => $intStripePaymentMethodId
                ,'confirm' => true
                ,'customer' => $intStripeCustomerId);

And later on, when I create a PaymentIntent with hte intention of completing a transaction at that time, I pass this data:

$arrData = array('amount' => (123 * 100)
,'currency' => 'gbp'
,'customer' => $strCustomerId
,'confirm' => true
,'off_session' => true
,'payment_method' => $strPaymentMethodId
,'payment_method_types' => array('card'));

If I change the payment intent to be this:

$arrData = array('amount' => (123 * 100)
,'currency' => 'gbp'
,'customer' => $strCustomerId
,'setup_future_usage' => 'off_session'
,'payment_method' => $strPaymentMethodId
,'payment_method_types' => array('card'));

...I still end up with a Payment Intent showing a status "requires_confirmation".

Once I've completed the 3DS process with the customer, what should I subsequently pass in to my PaymentIntent to complete a transaction against their stored payment method?

flint trellis
#

Once I've completed the 3DS process with the customer, what should I subsequently pass in to my PaymentIntent to complete a transaction against their stored payment method?
the second code snippet you posted does exactly that, so you'd use that. It works fine.

#

not sure what the context of the third snippet is and when/why you do that, can you elaborate?

night knoll
#

So the first screen collects payment details, connects to Stripe's API, creates a Stripe Customer, a Stripe Payment Method, attaches the Payment Method to the Customer and then creates a Stripe Setup Intent.

WHen I create hte SetupIntent, I do so with this data:

$arrData = array('usage' => 'off_session'
,'return_url' => 'https://xxx/'
,'payment_method' => $intStripePaymentMethodId
,'confirm' => true
,'customer' => $intStripeCustomerId);

The SetupIntent shows a status of "requires_action" so I use the URL from $setupIntent->next_action->redirect_to_url->url and I show that in an iframe. This is effectively the 3DS verification for the customer and they complete that online.

At a later date when I need to take money from the customer, I create a PaymentIntent and pass this data:

$arrData = array('amount' => (123 * 100)
,'currency' => 'gbp'
,'customer' => $strCustomerId
,'confirm' => true
,'off_session' => true
,'payment_method' => $strPaymentMethodId
,'payment_method_types' => array('card'));

...but I think you're suggesting that I pass this data:

$arrData = array('amount' => (123 * 100)
,'currency' => 'gbp'
,'customer' => $strCustomerId
,'setup_future_usage' => 'off_session'
,'payment_method' => $strPaymentMethodId
,'payment_method_types' => array('card'));

Either way, I don't get a complete transaction showing in my Stripe account.

flint trellis
#

, creates a Stripe Customer, a Stripe Payment Method, attaches the Payment Method to the Customer and then creates a Stripe Setup Intent.
note that's the wrong order. It should be, create Customer, CreatePaymentMethod, create the SetupIntent + confirm the SetupIntent(passing customer and payment_method and confirm). The SI will attach the card automatically when it succeeds, you don't need to and shouldn't call the manual customer attach method.

The SetupIntent shows a status of "requires_action" so I use the URL from $setupIntent->next_action->redirect_to_url->url and I show that in an iframe. This is effectively the 3DS verification for the customer and they complete that online.
sounds good. Note it's not "for the customer", it's just for that one set up. Future payments may or may not require 3DS, depends if their bank honors the exemption for merchant-initiated-transactions. But everything you're doing there is correct yes

At a later date when I need to take money from the customer, I create a PaymentIntent and pass this data:
looks perfect

...but I think you're suggesting that I pass this data:
100% not no? I'm saying that you are passing setup_future_usage, I linked you to the request ID where you do(https://dashboard.stripe.com/test/logs/req_Wi1rqQD8VoTDiP) and I explained how that is wrong and not what's in the docs(what's in the docs is what is in your second code snippet, which is correct and is what you should use and will work fine)

#

Either way, I don't get a complete transaction showing in my Stripe account.
do you have an example pi_xxx where you did the off session PaymentIntent using the exact code from the second snippet that is still incomplete?

night knoll
#

Yes: pi_3M0Q2ABZ9qUe1kQ515VOheBS

flint trellis
#

you can see it passed setup_future_usage

#

there is no way whatsoever that PaymentIntent came from that second code snippet

#

so you are not running the code you think you are

night knoll
#

This is my PHP code that runs when I create the PaymentIntent:

$arrData = array('amount' => (123 * 100)
                ,'currency' => 'gbp'
                ,'customer' => $strCustomerId
                ,'setup_future_usage' => 'off_session'
                ,'payment_method' => $strPaymentMethodId
                ,'payment_method_types' => array('card'));

$paymentIntent = $stripe->paymentIntents->create($arrData);

$strPaymentMethodId is the id of the payment method created previously.

flint trellis
#

?

#

like yes, that code is wrong

#

the correct code is

$arrData = array('amount' => (123 * 100)
                    ,'currency' => 'gbp'
                    ,'customer' => $strCustomerId
                    ,'confirm' => true
                    ,'off_session' => true
                    ,'payment_method' => $strPaymentMethodId
                    ,'payment_method_types' => array('card'));
#

as we've established multiple times now

#

so why aren't you using that? If you do, and you use the 3155 card previously set up via a SetupIntent, it will just work.

night knoll
#

Why are you being so hostile? Is this the way Stripe Customer Support works?

flint trellis
#

are the next steps clear? what can I clarify?

night knoll
#

Yep, and we've spent over 2-weeks talking to a variety of Stripe representatives who haven't been much help at all... so perhaps a degree of patience wouldn't go amiss?

flint trellis
#

I have no way to know that, sorry you have that experience

#

anyway, I've unblocked you(in 10 minutes), can you make the changes and let me know what happens?

night knoll
#

I have a PaymentIntent (ref pi_3M0Q9pBZ9qUe1kQ51cQVEdOF) which shows a status of success. ๐Ÿ™‚ This is obviously completed in the test environment though, with test card 4000002500003155. If I had completed the same process in live with a real card, am I right to think that all future transactions that we process against that customer's payment method would go through sucessfully without further 3DS intervention?

flint trellis
#

no, since it's up to the bank

#

in most cases that would be expected to succeed

#

that test card simulates the case where it suceeds

night knoll
#

OK - and if I were to use the JS SDK instead, does that affect the chances of future transactions succeeding / failing or is the situation the same?

flint trellis
#

the integration at that level makes no difference

#

you should still use the SDK though so you don't have to get PCI audited and certified and for better conversion/user experience using our optimised payment components

night knoll
#

So the bottom line is... we need to accommodate a situation where transactions fails because of 3DS requirements / complexities and in that instance, we need to get our customer back to the website to repeat the 3DS verification process... so that future transaction will go through OK until such time as the bank says "No" and we repeat the cycle once more?

flint trellis
#

that's a fair summary yes

night knoll
#

OK. And from our point if view, understanding whether a given transaction has succeeded or not is simply a case of looking at the status of the PaymentIntent after it's confirmed. Status = success and we know we've been paid; status of anything else and we know we haven't. More specifically, if the status = requires_action, we need to repeat the 3DS verification with the customer?

flint trellis
#

no, it would be status=requires_payment_method in this case (if the off-session PaymentIntent declines because of required authentication, we don't return status=requires_action, that's only done in on-session ; it's a bit of a quirk)

night knoll
#

OK. Thanks for your help.