#Shoesole-duplicate-transactions

1 messages · Page 1 of 1 (latest)

jagged sail
#

Hi there!

#

First, do you disable your pay button upon click?

worn gorge
#

Yep, we're running this (using jQuery), and that does disable the submit button:
$("#submit").disabled = true;

jagged sail
#

K, and how do you handle success?

#

Are you showing a clear indication of a successful payment?

#

The reason I ask is because if the payments are a couple minutes apart then that mostly just means customer-error/confusion.

#

Where they go all the way back through your checkout flow without realizing they successfully completed a payment already

worn gorge
#

I believe so, we send the user to a confirmation page and use this check:
if (in_array($paymentIntent->status, ['succeeded', 'processing'])) {

#

So, we're checking against succeeded, and processing as "good" responses and failing all others. Could that be it? Additionally we rely on webhooks to actually save the order in our DB and send the receipt emails.

jagged sail
#

If you weren't using webhooks then I would have said yes, that could be it, since the user could drop off before reaching your success page but after payment.

worn gorge
#

We have had SOME users say they got an error, but I feel like more would say that they are going through the entire process again, if they were.

jagged sail
#

But if you are ingesting data using Webhooks (which is recommended) then that should catch all payments

#

When do you create the PaymentIntent?

#

Can you walk through your flow?

worn gorge
#

We create a payment intent on the final page of our checkout where we display the payment form (however, I create the key used for indempotency earlier on, so I can reuse it if a person is editing their order, etc.

jagged sail
#

So you create it on page-load

#

What integration are you using?

worn gorge
#

Correct.

jagged sail
#

Payment Element?

worn gorge
#

Yes, payment element. Our code for setting that up on the front-end is pretty much from the docs.

jagged sail
#

Got it

#

Hmmm

worn gorge
#

I can share the JS we're using to create the element if helpful.

jagged sail
#

Nah that shouldn't really matter

worn gorge
#

k

jagged sail
#

What happens on a page refresh?

#

As in... you stated you tested the back button

#

When the page refreshes do you use the same client secret from the previous PaymentIntent?

#

To render Payment Element?

worn gorge
#

Good question. Let me verify.

#

Yeah, it appear it's the same each time I refresh.

jagged sail
#

I'm pretty stumped

#

Can you give me two PaymentIntents I can take a quick look at?

#

I don't think I'll be able to see much from my end

#

I think the best thing to do is going to be to contact a customer who has experienced this and try and get them to tell you exactly what they saw/did on their end.

worn gorge
#

Sure thing. You're wanting one that had a duplicate I assume

jagged sail
#

Yep

#

The two that are duplicates

worn gorge
#

One moment.

jagged sail
#

np

worn gorge
#

pi_3LbTGxQpbI6mU6Fo09FLBxSi
pi_3LbTMAQpbI6mU6Fo072lfJm7

#

The first one is the one stored within our DB, but the client reported a duplicate and that one appears to be it.

jagged sail
#

So the second one isn't in your Database at all?

worn gorge
#

correct

jagged sail
#

I mean I can see you responded to the Webhook

#

So that's really weird. You have something on your end that is filtering out ingestion of duplicates?

worn gorge
#

No, but it may be that something prevented it from actually saving on my end... like missing order info from our side (because we already cleared a cart). that's the flow I can seem to nail-down.

jagged sail
#

Mostly I don't think you are doing anything wrong. This really seems like customer error to me — 4 minutes is too much time for it really to be an integration issue (other than if your success isn't clear and the customer goes back through the flow, but doesn't sound like that is the case here)

#

But yeah

#

The database thing is something to investigate

#

Because that part is odd

worn gorge
#

For instance, what I originally thought was happening was a user getting to the "success page" after payment, hitting back and then resubmitting, but we clear out their cart and give and error if that is the case). That's worked for me in all my tests.

#

So, I THINK what I may do is add some logging on my end in the webhook (*since you can see that I responded to both those payment intents). and see what the rest of the order looks like, if anything at all.

jagged sail
#

Yep I think that is the right thing to do

worn gorge
#

Also, agreed that it seems there is a customer error in here. I wonder if I'm doing something in our UI to cause confusion to it.

jagged sail
#

Ah interesting. You do send a different response in the webhook

#

Which checks out

#

On the duplicate your response is blank

#

But on the initial one I can see you send back a <?xml version="1.0" encoding="UTF-8"?> <response><authUser/><createEventLink><controller>Promoters</controller><action>signUp</action><prefix>promoter</prefix></createEventLink><promoterTracking/><usePromoterBranding>0</usePromoterBranding><brandedPromoter>0</brandedPromoter></response> response

#

Which I assume just has to do with the order and some stuff

worn gorge
# jagged sail Which checks out

Yeah, that's definitely interesting. So the payload we're sending the second webhook is just empty... right now I'm just sending php://input in the payload... probably from some boilerplate. I could update that with something more useful... I'm so interested in why that second one is showing blank.

jagged sail
#

Yeah all of this is a bit strange. It almost does feel like there is a bug somewhere...

worn gorge
#

Also what's weird, totally different application fees on those two. Otherwise they seem identical.

jagged sail
#

I just am having a really hard pinpointing what it could even be

#

Oh I missed the different app fees

#

How is that set?

worn gorge
#

Welcome to my world. I've been staring at this code wondering what the situation could be that's causing this.

#

Let me verify how we set that.

#

We do it when creating the payment intent. It's based on the quantity of tickets sold in the order... which lends further credence to the idea that our cart is empty, or somehow changed.

jagged sail
#

Yeah

#

So maybe adding some logic to prevent payment confirmation with an empty cart

#

And add some logs there too

#

Even just log on page-load if the cart is empty?

#

Like... the customer should never be at that point with an empty cart, correct?

worn gorge
#

yeah, technically I can't event GET to the payment page without a cart. But I'll add some logging like mad just to see what the paths here may be.

#

I appreciate you taking the time to confirm I'm not entirely insane... I think it's simply something that's causing confusion.

#

Final question. I show a failure if the order doesn't have a status of pending or succeeded. There isn't any other type I could receive (from a regular payment) that would eventually succeed, is there?

jagged sail
#

When you say "pending" do you mean "processing"?

worn gorge
#

Yep, that's what I meant🙄

jagged sail
#

Yep no worries I figured. Yeah those two are the only ones that would indicate the payment can reach (or already-is) succeeded

#

Assuming you aren't using manual capture

#

Which doesn't look like you are

worn gorge
#

Yeah, okay. I thought so, good to confirm. Thanks I'll take some of these steps and see what I can determine. I'll follow-up if I find out more! Thanks.

jagged sail
#

Good luck!

worn gorge
#

Sorry, one other... I just saw this (and it also looks like a dup). But there is something interesting I see.

#

pi_3LcrqhQpbI6mU6Fo0IIdjWih

#

that one happened first, but it appears to have failed an zip code check but then succeeded.

#

Then this one happens a minute later and looks normal:
pi_3Lcrt2QpbI6mU6Fo0GUHG6ew

jagged sail
#

Yeah I mean overall that is the same really. Only main difference is that one looks to have an actual cart and the cart looks duplicated?

#

The failed payment is normal.

#

That decline would appear right in the Payment Element UI and the customer could try again with a different Zip

worn gorge
#

Yeah, I may totally be reading this wrong, but it seems like the one that had the address validation failure still succeeded, though? Or am I just missing something?

jagged sail
#

It succeeded on the second attempt

#

Not on the failure itself

#

This attempt was declined: https://dashboard.stripe.com/logs/req_IQhhek977n9HOq. Then it succeeded after they changed their postal code: https://dashboard.stripe.com/logs/req_Du4tlsozHsu3Jy