#Andora
1 messages · Page 1 of 1 (latest)
Can you share the subscription ID?
sub_1LuWn2BvZmAnxmFyN4YmSJfk
As you can see I had another plan before updating but it overwrite the existing subscription even though I canceled the auth
Right now I'm calling the update subscription method with payment_behavior = allow_incomplete on server side
What are you trying to achieve?
I'm trying to update an existing subscription and deal with the case where the user cancel the 3d secure auth. Because right now even if he cancel the 3d secure auth, the subscription stay incomplete and is overwritted with the new plan instead even though it should stay on the original plan before updating since it got cancelled
here are the step I follow
- Create subscription (server side) or Update subscription
- Check subscription.latest_invoice.payment_intent.status === "requires_action"
- Send subscription.latest_invoice.payment_intent.client_secret to the client
- Call confirmCardPayment using the payment_intent_secret
this work well when you don't already have a subscription, but if I already have one it will overwrite the existing subscription if I cancel and will stay in incomplete status and never go back to the original plan
I see! If you only want to update the subscription to new plan after the payment is completed, I'd recommend using payment_behavior=pending_if_incomplete: https://stripe.com/docs/billing/subscriptions/pending-updates
I tried payment_behavior=pending_if_incomplete but I don't have access to both metadata field and default_payment_method when using it
Which mean I cannot update the payment method if needed
I don't have access to both metadata field and default_payment_method when using it
Not sure what you mean by this. Access where?
this is how the call to update looks on server side
stripe.subscriptions.update(
existingSubscription.stripe_id,
{
items: [
{ id: subscription.items.data[0].id, price: plan.stripe_id },
],
default_payment_method: paymentSource.token,
metadata: {
plan_id: plan._id.toString(),
payment_source_id: paymentSource._id.toString(),
},
proration_behavior: "always_invoice",
expand: ["latest_invoice.payment_intent"],
}
I'm passing the payment method when updating
but if I use pending_if_incomplete these fields cannot be used
Sure, that's expected. The general approach here is to bring your customer back on-session to re-confirm the associated PI and complete 3DS, optionally providing an alternative payment method
In my case payments method are already setup but when calling subscription.update I can pass one of the already set up payment_method. Should I use pending_if_incomplete and if yes where can I pass the payment method ?
Well, you can't as pass them in the same call as you've discovered. You'd likely need to make 2 separate calls
Either way, your integration still needs to account for that fact that update the subscription may still trigger 3DS/auth request from the bank irregardless of if you've previously setup the card
Yes that's the case, it triggers 3d secure both when adding the payment method and also when updating the subscription which make sense
but is using pending_if_incomplete the correct way to update the subscription in case 3d secure got cancelled ?
Well, it just prevents the requested updates from applying until the associated payment succeeds if that's the desired behaviour
You can handle 3DS without pending_if_complete still, just means you'll need to manually rollback the updates if payment(s) fail
Ok so if I don't use pending_if_complete I need to roll back to the previous subscription plan ?
And I guess this is when receiving payment failed event from the webhooks right ?
https://stripe.com/docs/billing/subscriptions/overview#requires-action is probably more relevant in this case.
thank you. Last question, when receiving a failed payment intent in webhooks how can you retrieve the previous user plan before updating to another plan so it can be rollbacked
There's no automatic way to do that, it's a pretty laborious task:
You need to create a new invoice, prorate items on the invoice, and then initiate payment again. However, with the pending updates feature, you can make changes to subscriptions only if payment succeeds on the new invoice.
I see, thank you for your help
np!
Just wondering, any reason why invoice.payment_failed is called even before completing the 3d secure auth
because it's called twice for me, one before authorizing and second time when cancelling (this one make sense).
Sure, because the initial payment attempt (which triggers 3DS) is technically a failure
the issue I have is that I insert a new payment instance in my database when receiving the payment failed event. But since it fails even before completing the auth I have two payments inserted instead of one. Is there anyway to difference it to avoid inserting twice ?
Well it's technically the same payment, just separate attempts. The in_xxx is the same, as is the associated Payment Intent (pi_xxx)
Your modelling of it in that regard is wrong. You should map your payment instances against either the in_xxx or the pi_xxx, not on a payment_failed event
Not sure to get why it's wrong, each payment do have a payment_intent_id field in database which refers to the stripe_payment_id
But aren't my instance supposed to be created in webhook when listening to specific event ?
Because you're creating 2 payment 'instances' for what is the same payment/invoice
In reality, you'd probably update the 'instance' in your DB to reflect the failed status
yeah that make sense, which mean I should create the payment instance when listening to the invoice.created event and updating it when receiving invoice.updated right ?
Yes, that's how I would handle it
Make sense thank you