Just released the billing UI of @turnshiftapp. I never imagined it to be so complex. I spent a lot of time on it and learned about @stripe subscriptions, VAT rules, and Strong Customer Authentication (SCA).
Thread:
Thread:
Disclaimer: I am not your accountant and know nothing but what I learned from the internet about VAT and other rules. I am pretty sure I messed things up but

Vat rules:
Stripe has no API to automatically charge VAT taxes based on your customer's location (SURPRISE!).
You have to:
1. Ask customers for VAT numbers if they are in Europe and save it with tax ids https://stripe.com/docs/billing/customer/tax-ids. So their VAT number is shown on invoices
Stripe has no API to automatically charge VAT taxes based on your customer's location (SURPRISE!).
You have to:
1. Ask customers for VAT numbers if they are in Europe and save it with tax ids https://stripe.com/docs/billing/customer/tax-ids. So their VAT number is shown on invoices
Vat rules:
2. Create all vat rates using https://stripe.com/docs/billing/taxes/tax-rates and keep them updated. I use @crisp_im's node-sales-tax https://github.com/valeriansaliou/node-sales-tax/ inside a cron. (if rate changes, you need to deactivate and reassign to all customers)
2. Create all vat rates using https://stripe.com/docs/billing/taxes/tax-rates and keep them updated. I use @crisp_im's node-sales-tax https://github.com/valeriansaliou/node-sales-tax/ inside a cron. (if rate changes, you need to deactivate and reassign to all customers)
Vat rules:
3. Assign the right vat rate to customers based on their business location
4. Set customer's tax_exempt value: taxable (same country than your business, or no VAT number), exempt (if tax = 0) or revert (in EU, valid VAT number and rate > 0) see https://stripe.com/docs/api/customers/object#customer_object-tax_exempt
3. Assign the right vat rate to customers based on their business location
4. Set customer's tax_exempt value: taxable (same country than your business, or no VAT number), exempt (if tax = 0) or revert (in EU, valid VAT number and rate > 0) see https://stripe.com/docs/api/customers/object#customer_object-tax_exempt
SCA:
Strong Customer Authentication (SCA) is a new European regulatory requirement to reduce fraud and make online payments more secure. tl;dr; you have to more securely authenticate payment methods that you save for future use.
This page sums it well: https://stripe.com/docs/payments/save-and-reuse
Strong Customer Authentication (SCA) is a new European regulatory requirement to reduce fraud and make online payments more secure. tl;dr; you have to more securely authenticate payment methods that you save for future use.
This page sums it well: https://stripe.com/docs/payments/save-and-reuse
SCA:
When should you migrate? Soon. SCA rules are said to be rolled out through 2021 in most European countries. Stripe has a calendar: https://support.stripe.com/questions/strong-customer-authentication-sca-enforcement-date
When should you migrate? Soon. SCA rules are said to be rolled out through 2021 in most European countries. Stripe has a calendar: https://support.stripe.com/questions/strong-customer-authentication-sca-enforcement-date
SCA:
All I had to do was to create a backend route that is used whenever a customer adds a payment method. This route creates a PaymentIntent whose response can be used by the frontend to authenticate the payment method (3D Secure in most cases, via an iframe).
All I had to do was to create a backend route that is used whenever a customer adds a payment method. This route creates a PaymentIntent whose response can be used by the frontend to authenticate the payment method (3D Secure in most cases, via an iframe).
Subscriptions:
Weirdly I had trouble understanding how to easily create a subscription with either a monthly or yearly payment and trial period. Here's how to do it:
Create one product, with two prices (monthly, yearly). For the discount, I went for two months free.
Weirdly I had trouble understanding how to easily create a subscription with either a monthly or yearly payment and trial period. Here's how to do it:
Create one product, with two prices (monthly, yearly). For the discount, I went for two months free.
Subscriptions:
You get two price ids. And can use them on the frontend to let customers switch between the two.
You get two price ids. And can use them on the frontend to let customers switch between the two.
On your backend when a customer submits the billing form:
- if the price id changed, delete the old item, create a new one. Stripe will automatically charge
- if price id is the same, do nothing
- if the price id changed, delete the old item, create a new one. Stripe will automatically charge
- if price id is the same, do nothing
Now because this is a seat based subscription, you need to update the number of seats from time to time.
I have a cron that runs every day to update the quantity. For monthly plans, the difference will be charged at the next billing date.
But what about yearly?
I have a cron that runs every day to update the quantity. For monthly plans, the difference will be charged at the next billing date.
But what about yearly?
For now, I've created another cron that runs on the first day of each month, update the yearly quantity, and charge the customer immediately. This is what Slack does too: https://slack.com/help/articles/218915077-Fair-Billing-Policy#add-new-members-to-a-paid-workspace.
That's it, you're now ready to roll out your own custom @stripe checkout flow.
I was able to build this thanks to @crisp_im (for node-sales-tax), @reakitjs (for the nice Google maps autocomplete), the blog posts, examples, and guidance from @checklyHQ and @mergifyio about VAT rules.
Shameless plug: if you're doing team scheduling or team rotations via a spreadsheet, you might want to check out my product to replace them: https://turnshift.app .
See ya!
"Always Build in Public" © @PaulYacoubian
See ya!
"Always Build in Public" © @PaulYacoubian