#nbermudezs-pe-subs

1 messages · Page 1 of 1 (latest)

remote archBOT
drifting pier
#

Setup Intent

const stripe = new Stripe(CONFIG.STRIPE_KEY, { apiVersion: '2022-08-01' });

return stripe.setupIntents.create({
  metadata: {
    planId,
    userId,
  },
  usage: 'off_session',
});

off_session is important for us here because we hope to use the resulting payment method to charge the subscription once the free trial ends.

#

setup_intent.succeeded event handler

const setupIntent = body.data.object; // from webhook payload

const customer = await stripe.customers.create({
  payment_method: setupIntent.payment_method,
  email,
  invoice_settings: {
    default_payment_method: setupIntent.payment_method,
  },
});

const subscription = await stripe.subscriptions.create({
  customer: customer.id,
  items: [
    {
      price: metadata.planId,
    },
  ],
  default_payment_method: setupIntent.payment_method,
  trial_end: now.seconds() + TRIAL_DURATION,
  metadata: {
    method: 'payment-element',
  },
  expand: ['default_payment_method'],
});
#

(Our code for the Card Element is almost identical, except that it uses the PaymentMethod coming from the CardElement itself.)

Compared to the samples found online, our code differs in that when the setup intent is created it is not attached to a customer. We unfortunately cannot do that without a significant restructure because of assumptions made in our codebase when a Stripe customer exists for one of our users.

#

If it helps, here are some subscription IDs that failed for

  1. Payment Element flow: sub_1OcTsADnMwwVDHvuuMWnphza, sub_1Of9axDnMwwVDHvuE9Lgpcii
  2. Card Element flow: sub_1ODhJjDnMwwVDHvuT12Tl15n, sub_1OcEmIDnMwwVDHvuZj7NWONP
remote archBOT
#

nbermudezs-pe-subs

elder scaffold
#

Thanks for the details! Is there a reason why you're creating a SetupIntent directly and immediately before creating the Subscription with a trial?

#

Typically, SetupIntents are used to collect payment details from a customer if you plan on charging them in the future, but that "future" is hours/days+ from now

drifting pier
#

Thanks for jumping on this! My understanding (which can totally be wrong!) is that Payment Element needs either a payment intent ID or a setup intent ID to operate. Which means we need to produce that ID before we even attempt to collect the payment details. That's the reason we are currently creating the SetupIntent directly.

We are still charging the payment method days in the future (after the free trial expires) despite creating the subscription immediately after the setup intent succeeds.

remote archBOT
violet osprey
#

We support a flow where you render PaymentElement first and then when ready with payment method details you can get to your server to create the Customer/Subscription and get the PaymentIntent

drifting pier
#

thanks for the link! As I read through it I think the flow described means that a customer needs to be created (because it is needed to create the subscription) before a client secret can be obtained and the payment confirmed on the front-end.

For us that presents a challenge because the codebase makes a lot of assumptions based on whether one of our users has a stripe customer id or not. This is part of the reason we wanted to delay the customer creation until we have confirmed that the setup/payment was successful (e.g. waiting until we got the setup_intent.succeeded to do it).

I'm wondering if you see something wrong with our current approach that will really warrant moving to the deferred payment approach (and deal with its implications)