#shwallie

1 messages ยท Page 1 of 1 (latest)

inland blazeBOT
devout lance
#

Hi ๐Ÿ‘‹

#

What is the overall flow you are trying to accomplish here?

formal cove
#

We want a valid payment method associated with our user before we proceed with a subscription. So, a user will:

  1. Pick a product
  2. Submit payment method
  3. We'll validate the method (check for a CardError) and associate it with their Stripe Customer record
  4. Associate the credit card's address info (Country/postal code) with the Customer record
  5. Prepare a tax-inclusive fee break down for the user to review
  6. Create a stripe subscription & return the client_secret to the client
  7. Let use click stripe.confirmPayment to let the user start their subscription

If they unsubscribe, then come back, we'll jump to #5 if their default payment method is still valid.

devout lance
#

It's not too terribly different from what you are doing now but Setup Intents opitmize the payment method created for future off-session payments and perform necessary authorizations

formal cove
#

So - I create a setupIntent with my amount and currency then pass it's client_secret to the client to initialize the stripe.elements for creating a payment element?

That makes more sense if I understand correctly.

devout lance
#

Yes

#

Well you create the Setup intent with the Customer ID if you already have it

#

Then the payment method will automatically attach to the Customer if the confirmation is successful

formal cove
#

Curious - why don't I need a price_id/ amount & currency values when I initialize the SetupIntent?
https://stripe.com/docs/api/setup_intents/create

I was told that, to use createPaymentMethod properly on the client side, I needed amount and currency values there. To be honest, this makes more sense to me, but want to make sure I'm doing this correctly.

devout lance
#

Wait, are you following the deferred intent flow? but for a subscription?

formal cove
#

This is what I was driven to based on my past conversations:
https://stripe.com/docs/payments/accept-a-payment-deferred?platform=web&type=subscription

But - to be honest, I'm a bit confused on the difference.

Essentially, we want to use the Country/Postal Code the user enters to calculate tax on the subscription.

So, user picks the product, we collect the payment method (make it their default) and start the subscription when they've reviewed the final bill.

We also have a free trial for first time users... But want to have payment information on hand before starting the subscription (so we aren't driving them to the payment page when their subscription expires)

Build an integration where you can render the Payment Element prior to creating a PaymentIntent or SetupIntent.

devout lance
#

That makes sense. So in that case the reason you're passing the amount and currency even when you're not actually taking funds has to do with how Stripe.js creates the Payment Element.

#

The approach is secure

#

But it does feel a litle clunky

#

I've built that integration myself and it's kinda odd

formal cove
#

Yah - this whole thing feels clunky. I don't like it - but trying to cover our bases.

#

So - sorry, the prefered technique is to use the SetupIntent and use it's client_secret to setup the Stripe element?

devout lance
#

Honestly the deferred intent approach is the best way to be able to display the tax to be collected to the customer before they subscribe

#

To achieve what you're looking for.

formal cove
#

And - that works for both the free trial and non-free trial flow?

#

I just tested with the SetupIntent and it feels pretty good. Less stuff for the client to worry about. I want the client to be as dumb as possible

devout lance
#

For a free-trial you will get a pending_setup_intent property on the subscrpition instead of the latest_invoce.payment_intent but you can use either client_secret

#

Although yeah, if you want to push more of the handling to the server then Setup Intent will work

formal cove
#

Yah - I do that once I've created the subscription and then call either confirmSetup or confirmPayment depending on the free trial situation.

#

setup_intent = stripe.SetupIntent.create(
customer=customer,
usage='off_session',
automatic_payment_methods={
'enabled': True
}
)

return the setup_intent.client_secret to the client.

Client then:
const options = {
paymentMethodCreation: 'manual',
clientSecret: clientSecret,
};

elements = stripe.elements(options);

// Create and mount the Payment Element
const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');

///// user inputs payment details, then send it to stripe
const {error, paymentMethod} = await stripe.createPaymentMethod({
elements,
});

Assuming all is 200, then tell the BE to go ahead and make that the customer's default payment method and use it to initialize the customer's address information (for tax collection)

The user then sees the final invoice, with all the taxes
// continued

#

User sees final cost break down, and says "yah, let's do it". Client tells the backend to start the subscription

params = {
"customer": customer_id,
"items":[{
'price': price_id,
}],
"automatic_tax": {"enabled": True},
"payment_behavior":'default_incomplete',
}
if free_trial:
params["trial_period_days"] = 30

sub_result = stripe.Subscription.create(**params)
client_secret = sub_result.pending_setup_intent.client_secret if free_trial else sub_result.latest_invoice.payment_intent.client_secret

return the client_secret to the client.

Then, using the client_secret, the client will callstripe.confirmSetup (if free trial) or else stripe.confirmPayment;

Then our backend just listens to invoice.paid webhook events to provision the user's stuff on our side.

devout lance
#

Okay, that all seems to make sense to me

formal cove
#

Nice - thanks