#shwallie-paymentintent-tax

1 messages · Page 1 of 1 (latest)

echo sigilBOT
tribal pine
#

shwallie-paymentintent-tax

#

@steel shore taking a step back for a sec first: Why are you creating a PaymentIntent for a Subscription? Are you doing your own recurring logic/payment yourself?

steel shore
#

Hey - good question... Perhaps I'm doing this incorrectly! So, we want a user to setup their default payment method before starting the subscription. So:

  1. Create PaymentIntent
  2. Setup payment information
  3. Update customer to use payment method as a default method
  4. Use the payment method's Country/Postal Code to determine the 'final' cost of the subscription: sub total + tax(es)
  5. Provision the subscription (with an optional free trial)
  6. Use the subscription's appropriate client_secret to the client:
    6a: It's a free trial, use the pending_setup_intent.client_secret to call 'confirmSetup'
    6b: Non Free Trial, latest_invoice.payment_intent.client_secret (for a non-free trial) to call the 'confirmPayment'
#
  1. Listen to web hooks for customer.subscription.(created|updated) events to provision stuff for the user on our site
tribal pine
#

gotcha so yeah you're doing this wrong 🙂

#

Some developers don't like that integration path where they always create the Customer and Subscription upfront, though it's really better especially if you want to work with tax calculation and such upfront.

An alternative path is
1/ Collect payment method details upfront
2/ Create the Customer/Subscription server-side once ready to really pay
3/ Confirm the underlying PaymentIntent for that Subscription with the payment method details from step 1

That's what's covered at https://stripe.com/docs/payments/accept-a-payment-deferred?platform=web&type=subscription

steel shore
#

Okay - yah, we're more along the lines of the alternative path you provided and that's what I've got working. We use the payment method's country/postal code to setup basic address information for tax.

I don't know why, but I just dislike this code on the client: (https://stripe.com/docs/payments/accept-a-payment-deferred?platform=web&type=subscription#web-collect-payment-details)
const options = {
mode: 'subscription',
amount: 1099,
currency: 'usd',
};

I don't particularly understand what 'amount' is doing there. My subscriptions didn't seem to bill correctly when a free trial ended if I set it to 0.... And, 'amount' is also a bit of a lie since I don't have a total with taxes available at that time.

#

So - yah, that's why I was trying to initialize that with the PaymentIntent's client_secret, so I could provision it with a price_id on the backend.

tribal pine
#

Well that amount is just a placeholder really. You need some amount to show to the end customer. And many payment method types have strict validation (min/max amount, currency, 3D Secure, etc.)

#

As the developer, you would calculate the real amount your Subscription is going to Charge upfront. If you have a trial upfront, then you shouldn't use amount at all (but then there's no PaymentIntent either).
So taking a step back: are you taking a payment upfront?

steel shore
#

We want to collect/validate payment methods before the subscription starts. If it's a free trial, we'll expect the invoice to be paid using the information that was supplied when the subscription started. If the user is not eligible for a free trial, then they need to pay up front to start the subscription.

#

either way - the user's default payment method will be used by the subscription.

tribal pine
#

Yeah but the "either way" part is fundamentally different

#

There's a different between charging someone the full price upfront or just collecting card details for later

#

For a trial period the amount would be 0. For non trials it should be the exact amount you are going to charge on the first Invoice.

steel shore
#

Exact amount - so, tax inclusive

tribal pine
#

you can update, I have code locally doing that

#

I think our docs are incorrect here

steel shore
#

Okay - huh. Is this a valid flow at all? ie: Using a customer's payment method to determine tax? Feels like I'm 'fighting' with Stripe to make things work the way I want it to work, and I'd rather do things the 'Stripe Way' wherever possible.

tribal pine
#

I forgot you update the Elements instance, not PaymentElement

#

Anything else I can help with?

steel shore
#

Well - I guess is this the only way to using payment information to determine tax and also collect payment information before a free trial subscription is started? I just feel like my solution is getting a bit complicated.

tribal pine
#

I really don't understand what tax have to do with it

#

I'm sorry, we keep hitting this: If trial -> No payment, no tax. If no trial -> payment tax

#

Why are you trying to get the upcoming tax of the tax after their trial for example? For Stripe it's not "relevant" at least for the payment method collection

steel shore
#

Ha - sorry. But, if it's a trial, we want to tell our customer how much they'll be charged (including tax) when the trial ends. We want them to start being billed when the trial ends with no user interaction (unless their payment method is no longer valid, eg: insufficient funds, expired, etc, etc.

tribal pine
#

Yeah but that information is not provided to PaymentElement or Stripe and you would never create a PaymentIntent?

#

(just to make sure)

steel shore
#

Okay - I get yah. I'll stop trying to use the payment intent. Here's what I'll do:

  1. Let a user pick the product/price_id they want
  2. Use the unit_amount/currency to initialize the payment element, eg:
    {
    mode: 'subscription',
    amount: isFreeTrial ? 0 : unitAmount,
    currency: price_currency,
    paymentMethodCreation: 'manual',
    setupFutureUsage: 'off_session'
    }
  3. call 'stripe.createPaymentMethod'
  4. associate the resulting paymentMethodId with our customer as a default payment method
  5. Update the customer's address to use the payment method's country/postal code
  6. Use stripe.Invoice.upcoming with the customer & price_id to get a 'preview' of the price + taxes
  7. Let the client see the final charge (either now or after free trial elapses)
  8. Update the Elements instance's 'amount' field to be the tax-inclusive amount (or remain 0 if it's a free trial)
  9. Now that the user's seen the complete price, they can decide to start their subscription
  10. create a subcription for the customer.
  11. Return the appropriate client_secret:
    a) Free Trial: new_subscription.pending_setup_intent.client_secret
    b) Non-Free Trial: new_subscription.latest_invoice.payment_intent.client_secret
  12. Use the client_secret on the client-side
    a) Free Trial: stripe.confirmSetup
    b) Non-Free Trial: stripe.confirmPayment
tribal pine
#

yeah I think that should work

#

that's what I'd do

steel shore
#

Cool! And, in a situation where they unsubscribe and decide to resubscribe with a valid default payment method:

  1. Show them the tax-inclusive total (basically skip ahead to #9 from above)
  2. Create a subscription on the backend
  3. Use the new_subscription.latest_invoice.payment_intent.client_secret on the client to call 'stripe.confirmPayment'

Done.

tribal pine
#

yes!

steel shore
#

Okay - cool. Thanks for listening and the kick in the right direction.

tribal pine
#

Of course! I'm sorry this is so complex

#

people on my team kinda dream of a "Subscription element" where you give it price options and it does everything for you on your website. But that's more what Checkout and such offer instead

steel shore
#

Yah exactly - I wish there was a way for a free trial to not be considered started without valid payment information. But, since that first invoice is $0, then it turns to 'trialing' immediately. And, if a user doesn't complete the flow, then we'll have to do a bunch of extra logic if they decide to come back and 'resume' opting into our services.