#dev-commerciax_api

1 messages · Page 1 of 1 (latest)

dapper sonnetBOT
#

👋 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/1413112578783055932

📝 Have more to share? Add more details, code, screenshots, videos, etc. below.

paper crest
#

hey there! looking into your question now

scenic beacon
#

Sure, If you need any details, do ask for ti

fervent mist
#

hi there!

scenic beacon
#

*it

fervent mist
#

you should use proration_behavior: 'always_invoice'

scenic beacon
#

We tried

#

But what's happening is before we can authentication 3ds, the webhook recieved payment failed

fervent mist
#

and why is that an issue? what are you trying to do exactly?

scenic beacon
#

we are trying to allow user to upgrade subscripiton, And It works fine with first paid plan. but when user upgrades from one paid plan like Rs.349 to Rs. 699 some kinda error always occurs.

#

it works with create_prorations and default_incomplete but then it sends the remaining balance to next invoice

#

But we want to change immediately

fervent mist
#

some kinda error always occurs.
which error? can you share a failed Request ID (req_xxx)?

scenic beacon
#

but this setting: proration_behavior: 'always_invoice', payment_behavior: 'allow_incomplete', always gives some kinda error

fervent mist
scenic beacon
#

sure

dapper sonnetBOT
scenic beacon
glacial bough
#

Taking a look

#

Not seeing any failing update calls to the related subscription: sub_1S3ZweSCN5U3Z9OGqhLDaPx1

scenic beacon
#

Let me look and share another one

#

But this is basically what we are doing:

        items: [{ id: stripeSub.items.data[0].id, price: newPriceId }],
        proration_behavior: 'always_invoice',
        payment_behavior: 'allow_incomplete', // :warning: allows requires_action
        collection_method: 'charge_automatically',
        expand: ['latest_invoice.payment_intent'],
      });
 const invoice = updatedStripeSub.latest_invoice;
      const paymentIntent = invoice?.payment_intent;
 if (paymentIntent?.status === 'requires_action') {
        console.warn(
          `[upgradeSubscription] Payment requires customer action (3DS/SCA)`,
        );
        return responseHandler(res, 'Action required for payment', 200, {
          data: {
            requiresAction: true,
            clientSecret: paymentIntent.client_secret,
          },
        });
      }```
glacial bough
#

OK, but what's the exact issue with that API request? Does it error? What's the unexpected behaviour?

scenic beacon
#

So, basically what's happening is client secret is recieved from payment intent but before frontend could process that for 3ds auth, the subscripiton status goes to past due

#

getting this:

0|backend  |   oldPriceId: 'price_1RRo04SCN5U3Z9OGvfbs2JT9',
0|backend  |   newPriceId: 'price_1RRoUMSCN5U3Z9OG5hlHIHCF'
0|backend  | }
0|backend  | [upgradeSubscription] Error during Paid→Paid upgrade {
0|backend  |   message: 'Only active mandates can be used with PaymentIntents.',
0|backend  |   stack: 'Error: Only active mandates can be used with PaymentIntents.\n' +
0|backend  |     '    at generateV1Error (/home/backend/_work/neweb-backend-2/neweb-backend-2/node_modules/stripe/cjs/Error.js:11:20)\n' +
0|backend  |     '    at res.toJSON.then.Error_js_1.StripeAPIError.message (/home/backend/_work/neweb-backend-2/neweb-backend-2/node_modules/stripe/cjs/RequestSender.js:108:62)\n' +
0|backend  |     '    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)'
0|backend  | }
0|backend  | payment_intent.created
glacial bough
#

What's the client_secret?

scenic beacon
#

paymentIntent.client_secret

#

coming from this:

 const invoice = updatedStripeSub.latest_invoice;
      const paymentIntent = invoice?.payment_intent;

which is coming from here:

 const updatedStripeSub = await stripe.subscriptions.update(stripeSub.id, {
        items: [{ id: stripeSub.items.data[0].id, price: newPriceId }],
        proration_behavior: 'always_invoice',
        payment_behavior: 'allow_incomplete', // ⚠️ allows requires_action
        collection_method: 'charge_automatically',
        expand: ['latest_invoice.payment_intent'],
      });
glacial bough
#

I mean the actual client_secret value. I need some kind of object/ID so I can see what's going on

scenic beacon
#

we are not actually logging it

#

but it is something like in image: from frontend log -

glacial bough
#

Paste that pi_abc_secret_xyz please

scenic beacon
#
pi_3S3YPwSCN5U3Z90G1mxoB0s0_secret_E2njUghG5urPmkVzmK2TXzztE
glacial bough
#

Doesn't seem like a valid ID to me – can't find it in our system

scenic beacon
#

try this one: pi_3S3bBTSCN5U3Z9OG0apDPZLa_secret_EGLaUdCZ7vtIgWXeEdKkaHLbs

glacial bough
#

Taking a look

scenic beacon
#

sure, take your time

glacial bough
#

So yes, the subscription update (https://dashboard.stripe.com/logs/req_56B1GaNvs5FsPy) triggers a new invoice (and payment) which we try to charge for immediately. That fails however as 3DS/auth was requested (invoice.payment_action_required: https://dashboard.stripe.com/events/evt_1S3bBXSCN5U3Z9OG6u8Acgb2)

In that scenario, yes the subscription will transition to past_due as explained here:

Payment on the latest finalised invoice either failed or wasn’t attempted

You need to re-confirm the intent on the front-end via Stripe.js with your customer on-session to complete the 3DS/auth request and on success the subscription will transition to active

Manage recurring payments and subscription lifecycles.

scenic beacon
#

We are doing it but still the same error

glacial bough
#

I don't see any additional confirmation attempts on that PI

scenic beacon
#

That's the exact problem. before we could make 3ds auth on frontend, the webhook updates the subscripiton status to past due

#

Yes, no additional attempts has been made

#

on the frontend, we are doing this:

 if (result?.type === "requires_action") {
          // 👇 Use Stripe.js to confirm payment
          const stripe = await stripePromise;
          const { error, paymentIntent } = await stripe.confirmCardPayment(
            result.payload?.clientSecret
          );

          if (error) {
            toast.error("Authentication failed. Please try again.");
            return;
          }

          if (paymentIntent.status === "succeeded") {
            toast.success("Subscription upgraded successfully.");
            await dispatch(userActions.refreshUserData(token));
            window.location.href = `/billing/home?session_id=${Date.now()}`;
          }

          return;
        }

glacial bough
#

Sorry I don'y fully understand the issue. You've not given me a Payment Intent where there's an actual confirmation error other than from the sub update

glacial bough
scenic beacon
#

Server gives 500, before this could process

glacial bough
#

That 500 must be returned from your code, because I see no 500s in the examples you've shared

dapper sonnetBOT
rustic totem
#

👋 taking over for my colleague. Let me know if there's any follow-up Qs I can answer!

scenic beacon
#

testing the new code right now

#

will update soon

#

THis is the updated code and what's happening is it taking the propation amount to the next invoice

#

no 3ds auth asked

rustic totem
#

what's the behavior you're expecting?

scenic beacon
#

immediate charge with 3ds