#simon-says0363_api

1 messages ยท Page 1 of 1 (latest)

pulsar relicBOT
#

๐Ÿ‘‹ 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/1288232639991382027

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

median hearth
#

Due to the missing logs I can't provide log request ids, but I am happy to provide payment intent IDs if required and doing so is secure.

weary apex
#

Yeah please share the PaymentIntent ID

median hearth
#

It's happened to a couple, but here is the one I am currently investigating: pi_2Q0mpPTbTiK4Bfju23gkvyrD

#

According to our system we tried to charge that payment intent 11 times (timestamps UTC):

  • 2024-09-19T16:03:35.769+0000
  • 2024-09-19T16:03:42.734+0000
  • 2024-09-19T16:04:04.968+0000
  • 2024-09-19T16:04:09.871+0000
  • 2024-09-19T16:04:23.025+0000
  • 2024-09-19T16:04:28.078+0000
  • 2024-09-19T17:25:39.757+0000
  • 2024-09-19T17:25:45.294+0000
  • 2024-09-19T17:27:47.453+0000
  • 2024-09-19T17:27:52.641+0000
  • 2024-09-19T17:29:37.681+0000
#

But in the Workbench logs I only see 6 attempts.

#

And crucially the attempt that changed the payment method (17:29:37) is missing.

weary apex
#

I'm seeing only 5 requests made to /v1/payment_intents/:id/confirm meaning 5 attempts were made to confirm the PaymentIntent (6 including the confirm: true attempt from payment intent creation request)

median hearth
#

Yeah exactly. But I can see in our system logs that we made 11 requests. So something is getting lost somewhere.

#

Unless the Node SDK does caching?

weary apex
#

Does your system track which endpoints these requests were made to?

median hearth
#

Not directly, but I have enough logging that I can trace the code path it went through.

#

Using the npm package "stripe": "14.22.0" we made the following calls:

  • The first attempt called stripe.paymentIntents.create() (with confirm:true)
  • All the rest of the attempts called (in order):
    • stripe.paymentIntents.retrieve()
    • stripe.paymentIntents.update()
    • stripe.paymentIntents.confirm()
weary apex
#

Yeah I'm seeing update calls too. So your total number of requests isn't just confirm requests

median hearth
#

Kinda. I'm seeing 11 total api requests in the Stripe Workbench. 1 initial creation request then 5 pairs of update and confirm. But our system reports 1 initial creation request then 10 retrieve/update/confirm triplets.

#

So there are 5 more update/confirm pairs missing from the Stripe workbench, and also all of the retrieve calls as well.

weary apex
#

Is it possible that your logs duplicated these? Like I'm not aware of any issues on our end which could cause request logs disappear. We haven't heard any other reports of this too..

Anyway, taking a step back to look at the issue you've reported with payment method, what payment method object were you expecting and what are you seeing?

median hearth
#

It's highly unlikely unless we somehow have a network cache I'm unaware of. But given the request pattern that also seems unlikely.

#

Here's the map of our logs to Stripe requests:

  • 2024-09-19T16:03:35.769+0000 -- req_OWgcgETZNYuvF4
  • 2024-09-19T16:03:42.734+0000 -- req_n7ZLtAmZo0WZG1 + req_0HwkbKIM0hbufA
  • 2024-09-19T16:04:04.968+0000 -- req_rstZ0DXYMk99M5 + req_pGH1hyHmnmATvY
  • 2024-09-19T16:04:09.871+0000 -- missing
  • 2024-09-19T16:04:23.025+0000 -- missing
  • 2024-09-19T16:04:28.078+0000 -- req_fdymXZ65l40H4n + req_HmzxAeB07ctaUT
  • 2024-09-19T17:25:39.757+0000 -- missing
  • 2024-09-19T17:25:45.294+0000 -- req_6WvoVsLsbQ6AFW + req_2yF4OypQPIOA1W
  • 2024-09-19T17:27:47.453+0000 -- missing
  • 2024-09-19T17:27:52.641+0000 -- req_1CFnbLRqaZ8M7s + req_QzawUzL7omeByp
  • 2024-09-19T17:29:37.681+0000 -- missing
#

The final update/confirm pair says in our logs that it used pm_0PwW6kTbTiK4BfjuQOo4BpzN, but pi_2Q0mpPTbTiK4Bfju23gkvyrD lists pm_0Q0o8eTbTiK4Bfju4sRC6ip0

pulsar relicBOT
median hearth
#

I'm stumped. I can't think of any reason why this would be happening. Every idea I have doesn't hold up under scrutiny.

cinder turtle
#

๐Ÿ‘‹ Stepping in for my teammate, give me a few minutes to catch up please

median hearth
#

Yeah. That's the last pair I see Stripe as well.

#

But I see one more in our logs

cinder turtle
#

Do your logs include any details about a response received from Stripe for that update request?

median hearth
#

Yeah, it says it got back a Payment Intent with status requires_action

#

Oh wait I misread your question.

#

I don't have any response logged for the update request, just that it didn't throw.

#

The confirm request returned with requires_action

cinder turtle
#

just that it didn't throw
What does this mean exactly?

median hearth
#

The code in question looks like this (slightly tweaked for brevity):

// Update payment intent just in case details have changed.
await this.stripe.paymentIntents.update(
  paymentIntentId,
  {
    amount,
    currency: 'usd',
    customer: stripeCustomerId,
    description: label,
    payment_method: cardId,
  },
  { maxNetworkRetries: 2 },
);

// Initiate charge
const paymentIntent = await this.stripe.paymentIntents.confirm(
  paymentIntentId,
  {
    capture_method: 'automatic',
    off_session: !isOnSession,
    payment_method_options: {
      card: {
        request_three_d_secure: isOnSession ? 'any' : 'automatic',
      },
    },
  },
  { maxNetworkRetries: 2 },
);

if (paymentIntent.status === 'requires_action') {
  // Handle 3D Secure
}

I can see in the logs that it is making it to the Handle 3D Secure case, which means that the call to stripe.paymentIntents.update() returned a Promise that resolved, it did not throw/reject, and stripe.paymentIntents.confirm() also resolved, this time to a PaymentIntent with status: requires_action

cinder turtle
#

Hm, not exactly

median hearth
#

Hmm?

cinder turtle
#

No, nevermind.

median hearth
#

Yeah I've had a few of those moments looking at this issue so far ๐Ÿ˜…

cinder turtle
#

I think it'd be helpful to add some logging after your update

median hearth
#

To make sure the update worked you mean?

cinder turtle
#

Right

#

or to print/log which PaymentMethod will be used for the confirmation call

median hearth
#

Yeah, I'm adding a sanity check after the update call to make sure the result is what we expect.

#

Question about that actually. I see in the Workspace logs that you have only mostly redacted client_secret values. I'd like to replicate that in our logs so we can cross-reference. Is it safe to replace all but underscores in the middle?

#

Assuming that it is just failing to update though, what would that mean?

cinder turtle
cinder turtle
median hearth
median hearth
#

And I have no idea what to do with that information.

cinder turtle
#

As part of testing, can you retrieve the PI prior to confirming to ensure it's what you expect?

median hearth
#

Yeah, I'm adding that in.

#

I just don't know what that will tell us.

#

If it passes, then we're back to square 1, and if it doesn't then the update call is being swallowed without a trace. But both already seem to be impossible.

#

We're clearly missing something.

#

But what??

#

Woah.

#

Ok I was just able to reproduce it in test mode.

#

Now I need to reduce it down to a minimal repro.

cinder turtle
#

Ooh interesting

median hearth
#

......... ๐Ÿคฆโ€โ™‚๏ธ found it

#

Yeah the Stripe API is fine, we're just doing something dumb

#

Here's what we're actually doing:

let paymentIntent = await this.stripe.paymentIntents.retrieve(
  paymentIntentId,
);

if (paymentIntent.status === 'requires_action') {
  // Handle 3D Secure
}

// Update payment intent just in case details have changed.
await this.stripe.paymentIntents.update(
  paymentIntentId,
  {
    amount,
    currency: 'usd',
    customer: stripeCustomerId,
    description: label,
    payment_method: cardId,
  },
  { maxNetworkRetries: 2 },
);

// Initiate charge
paymentIntent = await this.stripe.paymentIntents.confirm(
  paymentIntentId,
  {
    capture_method: 'automatic',
    off_session: !isOnSession,
    payment_method_options: {
      card: {
        request_three_d_secure: isOnSession ? 'any' : 'automatic',
      },
    },
  },
  { maxNetworkRetries: 2 },
);

if (paymentIntent.status === 'requires_action') {
  // Handle 3D Secure
}
#

So if we attempt to charge a second time while the payment is still in requires_action we short-circuit and never update or confirm.

#

Which explains all the issues I was having.

cinder turtle
#

Ohh interesting

median hearth
#

So yeah, entirely our fault. Thanks for the help being a rubber duck. ๐Ÿคฃ