#dejwsiu

1 messages ยท Page 1 of 1 (latest)

vague pollenBOT
leaden crater
#

Hi, can you share the document you're following? What are you trying to build exactly?

#

It looks like you're trying to create a subscription?

left cove
#

Hi there โœŒ๏ธ. More details:

  • I'm trying to update existing subscription that can go thru 3da auth
  • first step in the process - i retrieve existing subscription and show it details in the view. core of the update would be quantity in volume based pricing
  • user selects does he wanna lower or higher this quantity
  • im sending this to backend to trigger stripe.subsciptions.update method
#

What would be my next move?

#

With standard cc it goes thru

#

With 3ds its giving an error

leaden crater
#

To rephrase your question, you're trying to update and existing subscription and would like your customers to go through 3DS again? Why? How is your current subscription flow look like? Trying to see if you've set Payment Methods etc.. Can you share any request ids that I can take a look at? Here's how you can find a request ID: https://support.stripe.com/questions/finding-the-id-for-an-api-request

left cove
#

My existing integration is based on old Payments API. I'm trying to move to Prebuilt Checkout for new subscriptions + adapt existing method of subscriptions.update to allow users to go thru 3ds if needed

#

Maybe it's not needed with update?

#

Documentation says it may happen while updating existing sub

#

As above - sub.update is used only for updating quantity in subs

leaden crater
#

Which document are you referring to? I want to make sure that we are looking at the same thing and that I fully understand the question.

left cove
#

payment_behaviour parameter description is referring in couple places to SCA/3ds

#

As I understand it works - i get an event with info that action is required, that have link for continuing the process (next_step as far as i remember response)

leaden crater
#

Can you share this specific request id with me please?

left cove
#

u mean id of primary request for subscription update?

leaden crater
#

Yes please.

left cove
#

thats id from response -> sub_1MWqa5KzEuaxuUK8jnf6sxBy

leaden crater
#

Taking a look

tender pewter
#

Just to confirm, all you're trying to do is handle 3DS in the case it's needed at a future date when the customer increases the subscription's quantity/how much they pay?

left cove
#

I want to make sure that if subscription.update method will be triggered, if 3ds will be needed, customer will be redirected to finish that process

#

So what I'm looking for is a "good practice" scheme

#

What to do if that happens

#

So i can align logic around this

tender pewter
#

Sure but like that's all theoretical

#

like what have you tried?

left cove
#

And docs don't say nothing about that

tender pewter
#

sure sure, let's ignore all of that. Let's solely focus on what you tried to do and what the problem is

left cove
#

I tried Customer Portal integration but that's not alignable for my specific situation cuz i have 30+ products

tender pewter
left cove
#

if think we're still not getting the point, so maybe treat me like a 5 year old boy for a moment ๐Ÿ˜† . im making a call to api to update subscription (let's pretend that for this example payment_behaviour is set up to 'allow_incomplete'). 3ds is required and payment is waiting for action. nothing shown up for customer, nothing got triggered in the backend. what should happen after that call?

#

lets say i have no code after that

#

what should be next? should i get some information from response on that call on frontend? should i listen to some event?

tender pewter
#

hum

left cove
#

whats the architecture for this

tender pewter
#

1/ Update the Subscription
2/ Read the response, based on that decide what to do.
3/ If the underlying Invoice you created doesn't have status: 'paid' then you have to figure out why and then get the customer to pay

left cove
#

1/2. so that's response for this call when 3ds is needed

tender pewter
#

please don't dump an entire object like that

left cove
#

i dont see any information on success/fail/needed actions. should i do something next?

tender pewter
#

This is a Subscription. I was talking about the Invoice.

#

You can see your Subscription has status: 'past_due' which means the most recent Invoice wasn't paid. But that doesn't always prove much (it could have been past due before your upgrade)

left cove
#

ok, so we have some step ahead? cuz this is response from inital call to subscription.update method

tender pewter
#

When you update the Subscription you need to pass expand: ['latest_invoice.payment_intent']. This will return the full Invoice in_123 and the full underlying PaymentIntent which you can then use to handle client-side confirmation/3DS if needed.

#

It's... really convoluted, especially if you have started with Checkout

#

The idea is basically: A Subscription represent the "overall recurring payment state machine". So you have a customer on a $10/month Price that renews on the 21st of each month. That's the Subscription. Each cycle, on the 21st, a new Invoice is created. That Invoice represents the "record of what they owe". The Invoice is associated with a PaymentIntent which is the lifecycle of that given payment (all their attempts, with some that might fail, until it succeeds

#

So you have Subscription sub_AAA. On creation it gives you an Invoice in_123 and the Subscription has latest_invoice: 'in_123'. That Invoice has an associated PaymentIntent pi_876 (assuming a payment is needed, here $10).
All of those objects have their own state/status. Like you could have the first 2 Invoices paid, the 3rd one you voided (no one will pay), etc.

#

Now, it's Feb 1st, you want to change their quantity. By default we don't take any payment, we just calculate the prorated amount the customer owes you and we'll add it to their next Invoice on Feb 21st.

#

But if you want to charge them now, you have to say "hey please invoice them for the difference now". You do that by passing proration_behavior: 'always_invoice'.
That means your Subscription sub_AAA has status: 'active' and latest_invoice: 'in_789'. Now you create a brand new Invoice for the price difference and you have latest_invoice: 'in_CCC'. If the payment succeeds => all good, nothing to do.
But if it fails you have to figure it out. Maybe the bank declined for insufficient funds, maybe they want 3DS, maybe the card was deleted/lost since, etc.

So in that case, when you update you basically tell Stripe "Hey I'm also going to need the full Invoice and the full PaymentIntent so that I can make sense of all of this please" (that's what Expand is see https://stripe.com/docs/expand)

So when you make that update you can then look and confirm that
1/ The Subscription has status: 'active'
2/ The Invoice in latest_invoice has status: 'paid'
3/ The PaymentIntent in latest_invoice.payment_intent has status: 'succeeded'

#

If 3DS is needed, then #3 above would havr status: 'requires_payment_method'. Same if the bank said "nope sorry, not enough funds".
In that case you go back to the client/front-end and you tell your customer "Hey looks like your bank said no, please enter new card details" and you render a new payment UI
Or you know, you just send the, to the Hosted Invoice Page: https://stripe.com/docs/invoicing/hosted-invoice-page

left cove
#

ok, thank you for this. so we have answer for question when we know something is wrong. should i retrieve then info from API to do next_action step or is it also someone hidden in initial response? i dont see it after expanding latest invoice

tender pewter
#

can you share the exact code you used?

left cove
#

core part:

#

const subscriptionParamsToUpdate = {
cancel_at_period_end: false,
quantity: subscriptionDetails.numberOfUsers,
proration_behavior: 'always_invoice' as Stripe.SubscriptionUpdateParams.ProrationBehavior,
payment_behavior: 'allow_incomplete' as Stripe.SubscriptionUpdateParams.PaymentBehavior,
expand: ['latest_invoice.payment_intent'],
};
let subscriptionResponse;
try {
subscriptionResponse = await this.stripe.subscriptions.update(subscriptionId, subscriptionParamsToUpdate) as any;

  console.log(subscriptionResponse);
} catch (e) {
tender pewter
#

So if you dump the whole object you should see the raw JSON with the full Invoice and PaymentIntent.

left cove
#

got it

#

got latest invoice expanded and payment intent inside

#

should i expand something more?

#

ok, im seeing next_action is not expanded

#

aaaand we're there

tender pewter
#

it's super easy

#

once you get to talk to one of us for 2 hours that is

#

It's definitely something we're aware of and want to improve, it's just not easy ๐Ÿ˜ฆ

#

again, the best option in my eyes would be to use the Customer Portal and never build this yourself

left cove
#

sry for being pain in the ass, but this is 4th way of support since couple of weeks and im tired of all blockers

#

ye, that was my desired choice, cuz we have like 3-4 years old integration

#

and all possible things are made wrong :p

#

so addapting this to checkout+customer portal is hell

#

and only reason for a change is 3ds, so ppl are counting my hours ๐Ÿ˜†

#

so im paying for tech debt made in my company years ago

#

thank u for your patience and time, hope i know everything i need now ๐Ÿ˜‡

tender pewter
#

I can say you don't, definitively

#

we haven't even spoken about "what happens if 3DS fails and they don't pay, what if I want to roll back the quantity change"

#

but you should have enough to start at least and then ask concrete questions with a clear example of the problem ๐Ÿ™‚

left cove
#

At least I know where to ask now ๐Ÿ˜† ๐Ÿค˜. Have a good night โœŒ๏ธ.