#skammerens-datter_api
1 messages ยท Page 1 of 1 (latest)
๐ 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/1265658771695341658
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- skammerens-datter_api, 17 hours ago, 16 messages
- skammerens-datter_api, 21 hours ago, 35 messages
- skammerens-datter_api, 1 day ago, 17 messages
- skammerens-datter_api, 1 day ago, 11 messages
- skammerens-datter_api, 2 days ago, 34 messages
- skammerens-datter_api, 4 days ago, 24 messages
and 4 more
hi! I'll have a look but to be clear nothing about that seems unusual, any payment any time can require 3D Secure
yes, but through the payment element that uses the setupIntent, the 3DS prompt opens, and I confirm it. The resulting invoice is then incomplete
ok yeah you're doing this way we do not recommend, creating a SetupIntent and then immediately doing a payment via subscription creation
but yeah this is all normal really. The SetupIntent does not prevent the on-session payment for creating the subscription requiring 3D Secure. It's for off-session payments.
okay; when doing it the regular way everything is fine, but I need my customers to be able to change the payment method. THey do that via a payment element and setupIntent, which is then the payment method they can use to create a subscription, or be charged for the next cycle. How else should I allow them to change the payment method?
what you have seems fine. When they are on-session and initiate a payment for a new subscription, that payment can require 3D Secure, that's just how it works.
The SetupIntent can set up the card so it qualifies for exemptions for off-session transactions (https://stripe.com/guides/strong-customer-authentication#:~:text=the customerโs bank.-,Merchant-initiated transactions,-(including variable subscriptions) , [0]on-session subscription creation is a different thing.
I assume in reality there is a longer gap between saving the payment method and then starting a subscription, it's only immediate in this case because you're testing?
okay, I'll elaborate my use case a bit then.
Our customer can select a plan, which will present them with a paymentElement that uses a paymentIntent to create the subscription. They can also downgrade, upgrade or cancel the subscription, or change the payment method.
That change is made using a setupIntent. For this test, I created the payment method (setupIntent) before choosing the plan, e.g. creating the subscription (other order would de facto be paymentIntent).
UI-wise, I can limit them to not create a payment method using the setupIntent unless they have a subscription already, which would ensure they run the paymentIntent for the subscription first.
Can I be sure, that the subsequent payments for the subscription will work with the changed payment method that was created using the setupIntent after the customer changes the method mid-cycle? Assuming the first method was added when creating the subscription using a paymentIntent?
If not, what should I do to ensure that?
ok let's break it down
can select a plan, which will present them with a paymentElement that uses a paymentIntent to create the subscription.
that is one flow. For that flow you want to be creating a Subscription and confirming its latest_invoice->payment_intent with the PaymentElement, that's all normal.
They can also downgrade, upgrade or cancel the subscription, or change the payment method.
these are all different flows. (but note you can replace all that with our CustomerPortal product).
===
downgrade, upgrade or cancel the subscription
for that you'd make the update, and if the change requires a payment, again it is confirming the subscripton's latest_invoice->payment_intent with the PaymentElement
or change the payment method.
that would be a page creating a SetupIntent and confirming it with a PaymentElement, then settingdefault_payment_methodon the Customer object to the PM that was used after it succeeds.
===
Can I be sure, that the subsequent payments for the subscription will work with the changed payment method that was created using the setupIntent after the customer changes the method mid-cycle?
you can never be sure of anything, any payment can decline, but if you added the card to the customer using a SetupIntent mid-cycle, then yes, that's good and all you can do and is done correctly with best chances of working.
okay, all that you describe is handled and working.
If I limit the setupIntent (change payment method) to only be useable UI-wise after the subscription has been created and authentication with 3DS, the subsequent billing cycle would use the new card added (also authenticated with 3DS) as if that was the initially used card with the paymentIntent?
If I understand you correctly, the issue only arises if the subscription is created almost immediately after adding the payment method and the 3DS is not yet updated with confirmed?
I am not sure if there are off-session limitations I am not aware of. I would like the only change in the subscription and how it's handled to be a new card that is billed per each cycle rather than the initial card that was used to create the subscription.
he subsequent billing cycle would use the new card added (also authenticated with 3DS) as if that was the initially used card with the paymentIntent?
the recurring payments use whatever is set asdefault_payment_methodon the Subscription or Customer(in that order). If you save a PaymentMethod to a Customer(confirming a SetupIntent) and set those fields, that is the PaymentMethod the next recurring charge uses.
If I understand you correctly, the issue only arises if the subscription is created almost immediately after adding the payment method and the 3DS is not yet updated with confirmed?
it doesn't generally make sense to save the card and do a "non payment" 3D Secure session, and then immediately charge the card(which then might need to also do 3D Secure), usually you do the payment and save the card during it(which is what confirming anincompleteSubscription's Invoice's PaymentIntent does).
okay, but now that it results in incomplete, will Stripe with Smart Retries charge the card afterwards and hopefully succeed?
it depends what you're referring to. Smart Retries is only for recurring payments, it doesn't apply when you create a Subscription with default_incomplete and are handling the initial invoice payment. If 3D Secure is required at that point it's expected that you present that to the user on the payment page and let them retry(call confirmPayment on the frontend) as needed.
I am not sure I understand the first part of your message. Are you saying, following https://docs.stripe.com/billing/subscriptions/build-subscriptions?platform=web&ui=elements#webhooks that Smart Retries does not try to charge the PM, since the subscription is created with payment_behavior of default_incomplete?
The second part of your message I am also doing
Smart Retries operates on the recurring payments only(the Invoices after the first one)
okay, that makes sense
let me create the subscription with 3DS, change the payment method (by setupIntent) and then advance the subscirption using test clocks to see if the subsequent payments are working as expected with the new payment method. I'll be back shortly
make sure you use the 3155 test card I linked to since that's the only one that simulates 3DS exemptions.
Yes, however what card should I use for the payment method change? Can I reuse the same, and it'll act as if it was another card (new payment method id)?
you can use the same number in all tests, it will always just be a new PaymentMethod object, there's no automatic de-duplication
Forgive me, but how can I check the payment method id of the first invoice, and the now subsequent charge for the new cycle? I have advanced a billing cycle using test clocks, and the new invoice is there and status of paid.
I just checked, and it was indeed working with the now updated card.
for instance you can call the Subscription Retrieve API and inspect the value of https://docs.stripe.com/api/subscriptions/object#subscription_object-default_payment_method
or from an Invoice, you can go invoice->payment_intent->payment_method
That was working as intended. I'll limit it so that the customer cannot change the payment method (create one) before a subscription has been created, since that would be where they would indicate the card initially, and the other way around is not needed. Thank you for your help.
Another question though, since I have also followed https://docs.stripe.com/payments/accept-a-payment-deferred?type=subscription the initial subscription has a payment method, rather than defaulting to the customer's payment method. I would like to simply have the one payment method on the customer. Is there a property I can set, e.g. this is on for the subscirption creation 'payment_settings' => ['save_default_payment_method' => 'on_subscription'] - should I remove that entirely, and it'll default to the customer's PM? I would imagine I'd have to ensure the customer's PM is set as default, rather than just being associated with the customer obj.
I don't 100% follow what "the initial subscription has a payment method, rather than defaulting to the customer's payment method" could mean, I'm sorry. Can you show me an example of what you're referring to?
Sorry ๐
Preferably the customer has no payment method associated, which is why I set on_subscription. However, the PM is also set for the customer, which seems redundant. The reason I am asking, is that with my code with the setupIntent, the PM on the subscription and the customer is changed, to keep everything 1:1, however it introduces extra logic and incoherence. Can I somehow make it so that the PM is not also added to the customer with a param?
no. I think what you're missing is the PaymentMethod object pm_xxx must always be attached to a Customer pm_xxx, that is where it lives. A pm_xxx can't just be "attached" to a Subscription sub_xxx, that is not the model. The model is "Customer owns a set of PaymentMethod objects; a Subscription for a given Customer can have the ID of one of those objects set as its default".
okay, so I could simply remove the 'payment_settings' => ['save_default_payment_method' => 'on_subscription'] ?
that would be a bad idea
ahah okay
if you do that, you still have a Customer with the saved PaymentMethod, but you will have nothing set on https://docs.stripe.com/api/subscriptions/object#subscription_object-default_payment_method , (since save_default_payment_method is supposed to set that for you autoamtically), and therefore all future payments will just fail because the Subscription has not been told what to charge.
so when changing the default payment method, I'd have to do it for both the customer and the subscription?
no, you can just set it on the description subscription. Refer to what I have shared earlier
the recurring payments use whatever is set as default_payment_method on the Subscription or Customer(in that order)
and the docs for https://docs.stripe.com/api/subscriptions/object#subscription_object-default_payment_method
ID of the default payment method for the subscription. It must belong to the customer associated with the subscription. This takes precedence over default_source. If neither are set, invoices will use the customerโs invoice_settings.default_payment_method or default_source.
okay, understood. For now I was also doing: $stripe->customers->update( $customerId, ['invoice_settings' => ['default_payment_method' => $subscriptionObject->default_payment_method]] );
you can do that too, it depends. In your case maybe that makes sense since you are creating mutlipe subscriptions per customer
what you'd probably like to be able to do is payment_settings' => ['save_default_payment_method' => 'on_customer'] but unfortuantely we haven't built that, it's a feature request
I have to run but hopefully that cleared some things up, handing over to @gleaming glen
okay - instead, I'll simplify by just updating the subscriptions's payment method. If it makes no issue to have several PMs on a customer, just that the PM of the subscription matches a PM of a customer, it won't matter that there are multiple PMs on the customer.
Just to clarify, we're not creating multiple subscriptions for the customer, simply replacing the payment method.
Okay, have a great day
I'd note that if you're creating a Subscription for a customer that already has a PaymentMethod and you want to use that, you can skip using the PaymentElement
you could just pass the ID of the customer's existing default PM to the frontend and call https://docs.stripe.com/js/payment_intents/confirm_card_payment#stripe_confirm_card_payment-existing to pay the latest_invoice->payment_intent
I think that's probably useful, since it sounds like otherwise you will have each new subscription creating a new PaymentMethod on the customer, which will quickly be really messy
Tahnk you, I am aware - I think we're misunderstanding eachother, but no matter, I got your point from previously. Go already, don't let me keep you ๐
Hello, catching up...
Yep that would make sense to do. Do you have any outstanding questions about managing these payment methods, subscriptions, and customers?
I was not quite sure what was meant by "sounds like otherwise you will have each new subscription creating a new PaymentMethod on the customer", since we're not creating more than one subscription per customer, we're just updating and downgrading them. The matter at hand was how to properly update the card/payment method. I simply want to replace one card with another, if the user submits a card in a payment element via a setupIntent. I think everything is working as intended
Gotcha thanks for the clarification though I am realizing that I may be misundersanding the situation. So the user is upgrading or downgrading the subscription and we are talking about how to change the default payment method that is used to pay for the new invoice that is created by that change, as well as recurring invoices generated after?
Yes. A paymentIntent and payment element create the initial subscription. It can afterwards be upgraded, downgraded, cancelled and more. The important thing, is that the customer can also click "Change payment method", which prompts another payment element with a setupIntent. If the user afterwards upgrades the plan, that generated invoice (prorated) is "Failed". The payment wasn't made; it says "DKK 282.20 payment was initiated which requires an additional user action" in_1Pg6lpGppVLMkw06d4jfcrQ3. I am unsure if this is simply because the 3DS takes a while and thus the upgrade couldn't be charged? If that is the case, I'll simply add a button to the invoice that will trigger the stripe.confirmCardPayment of the PM. I just need to be sure that the reason is the short time between the changing of payment method and the subscription upgrade.
because the 3DS was indeed confirmed
If the user wants to charge an existing saved payment method, you would not want to use the Payment Element or a SetupIntent. Those may still be useful to have on the page in case the user wants to add a new payment method. If they select an existing card, you can call confirmPayment and pass payment_method: 'pm_1234' where pm_1234 is the old payment method ID. Stripe will then charge that PM and display the 3DS modal if requested
I am not. I only show the payment element and setupIntent for the changing of the card. The payment element and paymentIntent for the initial subscription of the plan.
The issue is that the user can replace the PM (card with 3DS) for the subscription. If that is done, and the 3DS is even confirmed, the upgrade to a different plan afterwards using the stored payment method (which in this example was just replaced) the invoice is "Failed" and requires additional user action, which I do not understand why
THe issue does not occur, if the initial PM was not replaced.
Can you send me the ID of an invoice that saw that error? There shouldn't be additional actions required after that point if 3DS was completed
in_1Pg6lpGppVLMkw06d4jfcrQ3
I actually don't see 3DS being completed on that invoices payment intent at all
It looks like it went to failed because that action hadn't been completed before time advanced
I specifically pressed Confirm on the 3D Secure Test page 2
This is my third try of the same, with the same outcome
Do you have a public test page that I can try this out on?
That should not be happening if you are completing 3DS on our test page and getting redirected back
i set redirect to if_required, since it is only card payments
If the modal closes successfully then in that case
it does - that is what's strange... also, advancing the test clock, the subsequent charge for the next billing cycle of the subscription is complete, and did not require additional user action: in_1Pg6nyGppVLMkw06UCcGxLTi
That is interesting. You are using the "authenticate unless set up" card, once it is saved it will automatically succeed on off session payments (like recurring invoices) but it will require 3DS for on session payments. The subscription update that created the other invoice was not specified as off session
Can you deduce something from that, because to me I am unsure what to do to complete the integration
Right now, it sounds like 3DS may not be working as expected on your page. If you have a public test page that I can test this out on I am happy to take a look.
if you'd like, I can share the login credentials for a test account on our SaaS, so that you can try for yourself, I am just not sure where to send those credentials, since it seems this is a public thread
The thing we were just talking about is why 3DS was triggered or not triggered in the first place which is a separate but different thing. Basically when updating the subscription you indicated that your user was sitting at their computer and could complete 3DS, for recurring subscription updates we indicate that the user is not present which makes 3DS less likely. Our test card reacted as expected to you specifying both
That sounds great, you can DM me those credentials
just sent you the details. You should go to Settings in the left hand corner, and then Subscription tab
Gotcha, I am on the subscriptions tab now
i just severed the connection to the existing subscription, so maybe refresh depending on if it already has invoices and a plan chosen
Currently no invoices. If I switch plans should that generate an invoice that I can see this behavior with?
if you click Pro for instance, it should prompt for payment, which would generate a prorated invoice.
Hmm 3DS worked for me and completing the modal completed the payment properly
Have you tried this in another device or browser?
yes. now, what the issue is that if you go and change the payment method, it'll complete with 3DS again for that payment method, but if you then upgrade the plan to Enterprise, it'll generate an unpaid/failed invoice for that prorated amount.
so far we agree everything is working. the issue is with an updated payment method
also, next billing cycle with the new payment method will complete as per the previous invoices.
the issue happens when changing plans after having replaced the card with another
Ah, so what is happening is that the 3DS from the SetupIntent does not also cover the 3DS that is required for the invoice
Basically, banks can request 3DS any time that a payment or authorization happens
So completing 3DS to save a PM is good and in real life it makes 3DS on these changes much less likely
But, it always can happen and when it does happen the user needs to complete 3DS for that specific payment.
so you're saying what I have made so far works as it should?
Correct
The place where this is getting stuck is that you need to display 3DS to the user when you upgrade your subscription and the payment intent for the invoice comes back with a requires_action status https://docs.stripe.com/payments/3d-secure/authentication-flow?platform=web#when-to-use-3d-secure
okay, so to alleviate the issue of non-payment that is what I'd implement. But also, do I need to implement it for subsequent subscriptions billed, or does the 3D Secure cover the subscription now?
Hopefully the user should in most cases not have to come back and do 3DS, since the Subscription was confirmed. So if I understand you correctly, I should check requires_action and run stripe.confirmCardPayment on the PM?
3DS can technically happen on any payment. So you'll want to make sure you can present 3DS to the user when an upgrade requires it or when a normal recurring payment requies it
Again, in real life banks are very likely to say "They already completed 3DS here so I won't ask for it again" but for various reasons that isn't always the case so it is recommended that your integration should have a process for presenting 3DS to the user
okay, so besides doing stripe.confirmCardPayment on the PM if requires_action when the plan is actively changed on-session, and maybe just add a "pay now" button to the invoice lines that are unpaid for the subscription that happened off-session?
Yep that would be a great way to do that
Thank you - besides that, is it possible to include the unpaid amount in the next invoice, if it remains unpaid?
also, do we need to render a payment element, to be able to do stripe.confirmCardPayment? The intended use is just to present the 3DS prompt, and nothing else if it's on-session, and same thing goes for the "pay now" button
That is trickier unfortunately. We don't have an automatic way to do that, so you would need to cancel the old invoice and create invoice items for the same amounts just before the new invoice was created
okay, I get that. I'll look into implementing that if necessary
And no, you do not need to render a payment element to call confirmCardPayment here. Though that intent is already confirmed so you can actually use the handleCardAction call from that doc to present 3DS . Very similar call but that one doesn't even need a PaymentMethod ID
very nice, is that this: https://docs.stripe.com/js/payment_intents/handle_card_action ?
Yep yep
also, could I get you to sign out of the test account? I just need to reset the password and sign in in my end to get back to it
Yes, just logged out
thanks ๐ is it possible to keep this conversation open for a bit, so that I don't need to go through this again if I am so unlucky to reach another team member?
I actually do have to step out now but I've passed on the context to my teammate who is taking over. Apologies that it took me a bit to get on the same page, I was trying to catch up on too many things at once at first. They're already where it took me a bit to get to
hahahah you were quick enough, I just explained it a bit convoluted, since I am not too familiar with the Stripe lingo and methodology. Thank you so much for pointing me in the right direction
how can I retrieve the paymentIntent client secret per pompey's message?
Hello
You mean for the unpaid invoice?
Yes ๐
You can retrieve the invoice and expand payment_intent parameter
If you're trying to go from subscription to the invoice then you'd want to retrieve the subscription first while expanding latest_invoice
https://docs.stripe.com/api/subscriptions/object#subscription_object-latest_invoice
okay, but there are two separate cases:
- "pay now" button for the unpaid invoice that happened off-session
- confirm 3DS if need be when upgrading a plan on-session
does the latest_invoice.payment_intent have a clientSecret?
I'm not sure how that relates to retrieving the PaymentIntents?? Maybe I'm missing something here..
does the latest_invoice.payment_intent have a clientSecret?
Yup it should
I just thought I'd mention it to ensure you understood what I was referring to - being new to the conversation and all
Okay, I'll see if I can get it working
All good, let me know if there's anything else I can help with ๐