#ionu_api
1 messages ยท Page 1 of 1 (latest)
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.
๐ This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1283327269229821975
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
The 3184 card requires authentication on all transactions as mentioned here
yes, the popup for sca comes in, I hit complete, than with the pm, I try to do the payment intent. So it is confirmed
4000003800000446 for example needs confirmation at first payment. And it works
Oh I see, so you expect the PaymentIntent goes to requires_action, but it's declined straighaway instead?
well my process is like this : I create from js a confirmSetup, than the popup for sca comes in, I hit complete, and it goes to a backend request, with the pm_ and I do \Stripe\PaymentIntent::create() with payment_method added.
for the other 2 cards, having off_session = true just does the transaction, and all is ok. For the 3184 card it throws that authentication_required not even requires_action (the sca should have been confirmed for that pm anyway)
For the last point, the SCA is an engine but the card issuer still hold the last decision of whether or not to request or to decline the transaction. 3184 simulates such a case (which means it could happen in Live mode)
yes, but I confirmed the sca for it. How do I handle it? here is a video on the flow
Hi, can you upload some other video format. And btw I know what you are asking, looking around...
thanks ๐ I am converting it
I converted it into mp4, please let me know if it is ok
It seems like you confirm and authenticate the card successfully, but still get the error?
yes, I pass the pm to the backend, and from there I try to do the PaymentIntent. There I get that error
My initial guess, in your code, you save the error message somewhere, in this case authentication_required, and when the authentication is completed, instead of clearing the error, you show it to the user. I don't see any other ways how this could happen otherwise
I am popping the error as I get the result. The error is not saved. It is a try catch statement on \Stripe\PaymentIntent::create()
and this call is done after the user hit confirm. and comes with the success message. Isn't that when the authentication is complete ?
for example in the case of 4000003800000446 card, it follows the same process, and the payment is created ok
A successful authentication request to Stripe will not give you this error message, so it comes from an earlier step.
or 4000008260003178 gives insufficient funds
Could you please share your code?
Why are you creating a PaymentIntent but using confirmSetup()?
Wait, are you creating a PaymentMethod with SetupIntent and then charging it with a PaymentIntent?
This is a wrong approach.
What are you trying to achieve? Do you want to save the Payment Method for future usage?
yes.
we have right now the process with our own fields and we want to implement google pay. We have normal transactions and "recurring" payments that we process based on our calendar with the saved profiles. Because of that we need the future usage.
That the final amount is calculated in the backend, that is why the payment intent is done there.
in the old code we had 'setup_future_usage' = 'off_session', but I removed it
the old approach was :
this.stripe.createToken(this.cardNumber, this.setBillingData(stripeBillingFields)).then((result) => {
if (result.error) {
this.tokenizationResult.success = false;
this.tokenizationResult.message = result.error.message.replace(/(*)+/g, '***');
} else {
const {token} = result;
this.tokenizationResult.success = true;
this.tokenizationResult.token = token.id;
this.createTokenField(token.id);
this.updateSystemFields(this.adaptTokenizationResponse(token.card));
}
I see why 3184 card fails then:
You set it up correctly with SetupIntent and complete 3DS, but since it's "Always authenticate", when you attempt to charge it with PaymentIntent 3DS is required again and it fails.
yes ๐
in the old approach we had a different page for sca, and we handled it separately. There it works
I thought that if the method was authenticated, it was enough
Overall, your approach will work since normal cards don't work like this.
But I recommend you to calculate the amount and display it to the customer before charging them.
You can use setup_future_usage with PaymentIntents to save the card during payment instead: https://docs.stripe.com/payments/save-during-payment?platform=web&ui=elements
It's a card for testing edge cases, when auth is always required, even if it's set up. But it's not common.
we are showing it from javascript, but we still need to calculate it in the backend to prevent frauds
could we use some intermediate page for it ? like the old approach just for this
something like if we get that error, to try to authenticate again
If you create a PaymentIntent before collecting payment details, it can only be confirmed for the specified amount, no more no less. You should just calculate the amount, create the PaymentIntent on the backend (with setup_future_usage if needed) and send the client_secret to the frontend to confirm. It's the standard approach.
It's the most standard and recommended approach, and you won't need to worry about 3DS or anything: https://docs.stripe.com/payments/accept-a-payment?platform=web&ui=elements
I know there is an issue when too much time time passes between the initial click and the confirm payment intent (going to backend, calculate amount and doing the actual confirmation of the payment intent). Stripe considers it an automatic action instead of an user trigger
You create a PaymentIntent when the customer enters the checkout page. After that they have 24h to confirm the PaymentIntent on the frontend. There's no need to confirm it on the backend.
we need to create the payment method to store it for future charges. Also I need the payment confirmation on the spot, to know if it is a valid transaction
oh, they confirm it in the front, and than we have the details after the confirmation
store it for future charges
You can usesetup_future_usagewith PaymentIntents for this: https://docs.stripe.com/payments/save-during-payment?platform=web&ui=elements
I am just trying to clarify that your use case is very common, and you can use the most standard, most reliable solution for this. No need for complex integrations with multiple steps.
yes, setup intents was recommended by someone from stripe support, but at first glance the above is what we need. Thank you very much for your help. I will start working with the above and hopefully I will not come back for help ๐
Hey, taking over here. Let me know if there's any follow-up Qs I can answer!
we cannot create a paymentIntent on page load, because we do not know the final amount. Without the paymentIntent we cannot generate the payment element. How do we display the payment element without the amount already calculated ?
also we have this "Failed to execute 'postMessage' on 'Window': Delegation is not allowed without transient user activation" if we use the backend calculation for the amount and than confirm it in the front end. That is why we went for confirmSetup
So the main idea is that we do not have any info on the page load, and the amount is dynamic. We need to show the card details form before knowing the amount. ConfirmSetup does that for us, but we have the issue with that one card 4000002760003184 that throws the error.
How do we display the payment element without the amount already calculated ?
You can collect the PaymentMethod first then calculate the amount and then complete the payment using the saved PaymentMethod
https://docs.stripe.com/payments/save-and-reuse?platform=web&ui=elements
this is what we are doing with await stripe.confirmSetup. However, when using this specific card 4000002760003184 (This card requires authentication on all transactions, regardless of how the card is set up.) after clicking confirm for the 3d secure popup, the paymentIntent fails with
"outcome": {
"network_status": "declined_by_network",
"reason": "authentication_required",
"risk_level": "normal",
"risk_score": 37,
"seller_message": "The bank returned the decline code authentication_required.",
"type": "issuer_declined"
},
using 4000003800000446, or 4000008260003178 (for sca) or normal non-sca cards, work as expected
here is the video with the behaviour
can you post the SetupIntent seti_xxx from that video?
here is an example of the req req_ciYrpBpDDK5QOv, req_icOqjPEwMOvaoS, req_q3FWvjmiKV9EMk
let me get the seti
hmm this seems normal? you did the SetupIntent which succeeded, fine, and then you immediately tried to do a PaymentIntent on the saved card, which is expected to fail on that card.
seti_1Pxlr4G5NORjrd4mCa5mAuG3
it's the 4000002500003155 card, and only the 4000002500003155 card, that can be charged off_session and simulates getting an exemption from 3D Secure
in general also you should never do SetupIntent->immediate PaymentIntent, that's a bad flow as it can lead to double-authentication flows. You can create a PaymentIntent with setup_future_usage as mentioned earlier to charge + save the card
my issue is that with the old appropach, we did a separate page for sca, and that did not fail. it went through. There it was a status requires_action and after the sca was confirmed, it went through.
yes , because the behaviour is different when you confirm with off_session:true
my problem with the PaymentIntent is that we do not have the final amount when displaying the page. So because of "If you create a PaymentIntent before collecting payment details, it can only be confirmed for the specified amount, no more no less. You should just calculate the amount, create the PaymentIntent on the backend (with setup_future_usage if needed) and send the client_secret to the frontend to confirm" we cannot change it
oh, understood
when you confirm with off_session:true and the payment requires 3D Secure, it just declines(because you tell us the customer is not there so they can't do an action), so then you can contact the customer and re-confirm on-session(which does present 3DS and goes to requires_action)
so we could return them to a page and try to do a off_session:false with the old approach
yeah unfortuantely there's not great soution. I do suggest trying to optimise for the fewest number charges as possible so it's generally better to do one PaymentIntent than two, or a SetupIntent + a later PaytmentIntent.
options include
- use your SetupIntent + off_session PaymentIntent flow(if the payment amount really takes O(hours) to know and confirm)
- SetupIntent, contact the customer later when you know an amount and charge on-session PaymentIntent then
- PaymentIntent for some large-ish/estimated amount, with capture_method:manual, and then capture the amount you need(and if you need more, do an off-session PaymentIntent)
and this "SetupIntent, contact the customer later when you know an amount and charge on-session PaymentIntent then" is not falling into "never do SetupIntent->immediate PaymentIntent, that's a bad flow as it can lead to double-authentication flows" issue ?
not really since you'd be doing it O(hours) apart in a clearly different flow
well, the idea is that if I do the payment later, than I do not have the resolution on the spot, right ?
what I'm talking about is where you enter your card, you get a popup saying "Authenticate your non-payment authorisation to save the card with <merchant>" and you do that in your bank app, then two seconds later you get another popup "Authenticate your payment of $156 with <merchant>" and have to do that in your bank app too. That's a real flow/bug/issue I've had live merchants report to me and it's because they do SI->PI
sure but you said you don't know the amount on the spot
I don't know how long it takes you to calculate the amount. If it's literally just that you need one round trip to your server than https://stripe.com/docs/payments/build-a-two-step-confirmation could work I think
the amount is calculated based on the user interaction, but the page is already loaded with the payment form
then can't you just use the Deferred Intent flow where you don't have to create the PaymentIntent until after the user already entered their card details and pressed Pay?
seems like what you need(you're probably thinking you need the Intent-first flow where you create the Intent on page load, but over the last year we made the Deferred flow more supported)
https://docs.stripe.com/payments/accept-a-payment-deferred
there's a frontend amount you can control by updating Elements as the cart changes too
hmm, looks like it. I can add a payment in the elements options, and update it with elements.update({amount: newAmount}); THan in the backend I can still verify if any amount manipulations happened. I guess I can do here the confirmation of the payment in the backend as well with the "confirm" = true, and it would mimic the flow we have now
yes, that is what https://stripe.com/docs/payments/build-a-two-step-confirmation (an extension of the deferred flow)is about and it enables the concept of "send a token from the frontend, confirm the PaymentIntent on the backend"
ok, thanks. I will look into that. Also customerSessionClientSecret can be updated with elements.update(); ? The reason I am asking is that after the user adds the details, mainly the email, we want to identify if he already has a customer id on that email, and use it to add the payment profile. Not creating a new customer each time
yes it can be updated
ok, thank you. I will try this approach. I really appreciate the help