#dejwsiu
1 messages ยท Page 1 of 1 (latest)
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?
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
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
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
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.
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)
Can you share this specific request id with me please?
u mean id of primary request for subscription update?
Yes please.
thats id from response -> sub_1MWqa5KzEuaxuUK8jnf6sxBy
Taking a look
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?
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
And docs don't say nothing about that
sure sure, let's ignore all of that. Let's solely focus on what you tried to do and what the problem is
I tried Customer Portal integration but that's not alignable for my specific situation cuz i have 30+ products
like https://dashboard.stripe.com/test/logs/req_mdSVtSlCxu8XAc
this is an update, the payment failed, you can now handle 3DS on session
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?
hum
whats the architecture for this
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
1/2. so that's response for this call when 3ds is needed
please don't dump an entire object like that
i dont see any information on success/fail/needed actions. should i do something next?
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)
ok, so we have some step ahead? cuz this is response from inital call to subscription.update method
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 kind of this flow https://stripe.com/docs/billing/migration/strong-customer-authentication#scenario-3
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
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
can you share the exact code you used?
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) {
So if you dump the whole object you should see the raw JSON with the full Invoice and PaymentIntent.
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
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 ๐ฆ
we have many alternative flows too like https://stripe.com/docs/billing/subscriptions/pending-updates
again, the best option in my eyes would be to use the Customer Portal and never build this yourself
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 ๐
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 ๐
At least I know where to ask now ๐ ๐ค. Have a good night โ๏ธ.