- Stack: Nodejs/Vue/Stripe
- NOTE: Logic works for the standard card (4242424242424242), when trial does not exist even 3D cards work.
- This card is used for this test: 4000002500003155
Hi everyone, so the title pretty much says everything, I have an issue with 3d secure cards when trial ends.
Steps to reproduce: Node(SERVER):
- create customer
const customer = await this.getInstance().customers.create({ email: userData.email, name: userData.fullname, });
- create subscription
const subscription = await this.getInstance().subscriptions.create({ customer, items: [ { price: priceId, }, ], off_session: true, promotion_code, payment_behavior: 'default_incomplete', expand: ['latest_invoice.payment_intent', 'pending_setup_intent'], metadata, trial_from_plan: true, });
- return data to CLIENT side
const invoice = subscription.latest_invoice as Stripe.Invoice; const intentType = subscription.pending_setup_intent ? 'setup' : 'payment'; const intent = intentType === 'payment' ? (invoice.payment_intent as Stripe.PaymentIntent) : (subscription.pending_setup_intent as Stripe.SetupIntent); const formattedSubscription = pick(subscription,['cancel_at_period_end','cancel_at','canceled_at']); return { intentType, ...pick(intent, ['id', 'client_secret', 'status']), ...formattedSubscription, };
From the CLINET side:
- Fetching response:
const response = await this.$pricesService.buyPlan(this.selectedPlan.id, { fullname: this.nameOnTheCard, email: this.email, hash: this.couponApplied?.hash, }); if (response.error) { throw new Error(response.error); }
const { intentSecret, intentID, intentType, ...restOfBuyResponse } = response;
- Depending on the type of the intent:
if (intentType === 'payment') { stripeResponse = await StripeInstance.confirmCardPayment(intentSecret, { payment_method: { card: this.$refs.cardElement.$refs.element._element }, }); } else { stripeResponse = await StripeInstance.confirmCardSetup(intentSecret, { payment_method: { card: this.$refs.cardElement.$refs.element._element }, }); }
- Confirmation triggers 3d Secure modal and after confirming it, invoice on 0$ is paid.
Everything works as it should until this next point.
To test trail mode as fast as it can be done, I've made API to remove trial from the subscription
const subscription = await this.getInstance().subscriptions.update(subscriptionId, { trial_end: 'now', });
After that, Invoice is OverDue, subscription is failed (with switching to pending). I've noticed that default_payment_method is absent, so I've even returned setup intent payment method from the fronted, and attached to the customer, even invoice settings. But no matter what I've modified, new invoice and payment intent never used that information.
Is this expected behavior due to some regulations or am I missing something?