My Stripe Tax Story
I've been debating for weeks whether or not I was going to write any of this down. I'm a dad with two kids and a house to take care of and a business to run. Adding story-telling like this to my plate is exhausting.
Until yesterday, I had decided to forget about the whole thing, until I received the email that broke the camels back, as it were.
The best way I can describe why I'm writing this email is for the same reason why you might spend two hours dealing with an uncooperative mobile phone carrier to get them to remove that $5 charge on your bill that shouldn't be there. Some combination of the feeling of frustration and injustice that really pushes my proverbial buttons.
In this particular case, the "$5 charge on my phone bill" turned out to be literally hundreds of recurring subscription invoices that Stripe disabled collection for because, apparently, those subscriptions required "location inputs".
Generally speaking, I don't blog much anymore, and the last thing I want on my blog is some rant about some bad thing that happened to me, so I thought I'd just write it here instead.
And so, without further ado, here is my Stripe Tax Story.
"I have not been charged for December 2021 and January 2022"
It all started on January 21, 2022 when I received an email from a customer asking some questions about my SaaS product, and also mentions the following:
I have [redacted] and signed up using the email address [redacted]
I updated my profile with this email, [redacted] and noticed I have not been charged for December 2021 and January 2022. I didn't cancel my subscription, why would I not have been charged? [emphasis mine]
That's a great (and horrifying) question, and I am as confused as you are -- I'll take a look.
Low and behold, I take a look at the payments for this customer on my Stripe Dashboard and, sure enough, her invoices for December and January have not been charged or processed, but both invoices have been created and are in Draft state. At this point I am wondering what on earth could possibly be wrong, and admittedly had a bit of a panic attack as I began to wonder if this is affecting any other customers. I had noticed that my cashflow for the previous 2-3 months seemed to be tanking a bit, but my Stripe Dashboard was as hopeful as ever, reporting increased MRR and no problems in sight. Additionally, I use Profitwell (a tool for looking at financial metrics and doing churn recovery) which was also reporting overall increased MRR.
So despite the fact that cashflow in terms of actual cash coming in to my bank account was decreasing, I initially chalked it up to the timing of annual renewals and assumed it would level out.
But as I start digging in to this problem, I notice that I have a ton of customers who have not been billed as far back as November, with invoice after invoice after invoice created by Stripe just sitting there in a Draft state.
What in the hell is going on?
I switched accountants recently, and they told me I need to start charging PST (Provincial Sales Tax) for customers located in British Columbia, Canada (where my business is registered). I'd already been waiting for Stripe Tax to launch for Canadian subscribers because manually calculating taxes, which customers you have to charge taxes, how much tax, etc. is a huge pain. I was so happy that Stripe Tax was launching for Canada that I could barely contain myself. These guys were pros, amazing, and they were going to make my life so easy.
I built out my Stripe Tax integration, made sure I had all the addresses I needed for my Canadian customers (Canada is the only jurisdiction I run my business, and therefore only need to charge tax to Canadian customers), and updated all my customer subscriptions, awaiting the glory of automatic GST, HST and PST to be charged, and Stripe Tax taking all my headaches away.
I deployed it on November 6, 2021, the same day that Stripe stopped billing a significant number of my customers, left all their invoices in a Draft state, and didn’t tell me about it.
No emails. No dashboard notices. No failed API calls (as far as I could tell). Nothing.
I didn't figure this out until January 21st, almost three months later, and even then only because a customer was the one to point out the missing charge on her card.
Holy Sh**, time to contact Stripe Support.
So I reached out to Stripe Support on January 21st (the transcript that they emailed me after our chat was complete is included below in its entirety, with links to images that I uploaded to the chat redacted). This chat completed approximately Jan 21st at 1320 hours PST.
Hey there Daniel
Patrick here again from Stripe support and thanks for chatting in.
As discussed, a member of our team will be in touch with you soon via email.
All the best, Patrick.
(07:48:40 PM) Daniel Wintschel (email@example.com): Hi there, -- about 3 months ago (November) I enabled automatic tax via Stripe Tax for my small SaaS business.
(07:48:59 PM) *** Patrick joined the chat ***
(07:49:02 PM) Daniel Wintschel (firstname.lastname@example.org): Only today (facepalm) did a customer ask me why her subscription had not been charged for the past three months...
(07:49:35 PM) Daniel Wintschel (email@example.com): I dug into this issue further and I've found that I have hundreds of invoices that had automatic collection turned off on subscriptions because the tax could not be calculated...
(07:50:15 PM) Daniel Wintschel (firstname.lastname@example.org): So I am going to now have to try to go through hundreds of invoices and hundreds of customers to attempt to populate US zip codes in order to get these subscriptions up to date and try to back-bill customers 3 months of subscriptions...
(07:50:40 PM) Daniel Wintschel (email@example.com): 1) Is there a reason why Stripe didn't somehow notify me that this would happen, even in an automated way?
(07:50:46 PM) Daniel Wintschel (firstname.lastname@example.org): 2) Have other customers had this problem?
(07:51:12 PM) Daniel Wintschel (email@example.com): 3) Is there an easy recommended solution outside of hours of development time and contacting customers pretty much on a 1 by 1 basis to collect this information?
(07:52:15 PM) Daniel Wintschel (firstname.lastname@example.org): It's even more frustrating because I have no tax registrations in the US at all -- I am only trying to collect tax in Canada, and yet ALL or MANY of my US customers have had the past three months invoices automatically disable auto collection.
(07:52:37 PM) Daniel Wintschel (email@example.com): And my cashflow is obviously a bit in the crapper. -- now I know why.
(07:53:15 PM) Patrick : can I ask, where you saw that they were cancelled because of " automatic collection turned off on subscriptions because the tax could not be calculated..."
(07:53:51 PM) Daniel Wintschel (firstname.lastname@example.org): Visitor uploaded: [[redacted]]
(07:54:01 PM) Daniel Wintschel (email@example.com): Just starting with some screenshots -- here is one example.
(07:54:06 PM) Daniel Wintschel (firstname.lastname@example.org): Nothing showing why here...
(07:54:27 PM) Daniel Wintschel (email@example.com): but shows here..
(07:54:38 PM) Patrick : can I have one subscription id please ?
(07:54:48 PM) Daniel Wintschel (firstname.lastname@example.org): Visitor uploaded: [[redacted]]
(07:54:54 PM) Daniel Wintschel (email@example.com): When I dig in -- I get this.
(07:55:03 PM) Daniel Wintschel (firstname.lastname@example.org): But it is for literally hundreds of invoice.
(07:55:50 PM) Patrick : could you share some subscriptions ids please ?
(07:55:52 PM) Daniel Wintschel (email@example.com): Here is one subscription ID:
(07:55:53 PM) Daniel Wintschel (firstname.lastname@example.org): redacted
(07:56:19 PM) Daniel Wintschel (email@example.com): redacted
(07:56:46 PM) Daniel Wintschel (firstname.lastname@example.org): redacted
(07:57:02 PM) Patrick : OK thanks, let me see what I can find on this
(07:57:19 PM) Daniel Wintschel (email@example.com): redacted
(07:57:21 PM) Daniel Wintschel (firstname.lastname@example.org): Thanks
(08:06:59 PM) Patrick : you are very welcome
(08:15:22 PM) Patrick : thanks for waiting Daniel, I will need to send this along for further investigation for you, I will ask the team to email you back asap .
(08:17:02 PM) Daniel Wintschel (email@example.com): OK Patrick -- this is pretty devastating as the last thing I expected when I would implement this is three months of customers not being charged and now some untold massive amount of work to communicate with them and have to try to back-bill... who knows what churn or financial loss this will cause... I totally understand if I screwed something up, but I really need some very clear communication about what went wrong here (either on my part or on Stripe's part) - and I really need to know ASAP what to do.
(08:18:13 PM) Patrick : Of course Daniel, I can completely understand this an I will have the team dissect this and come back to you asap
(08:18:38 PM) Daniel Wintschel (firstname.lastname@example.org): Thanks Patrick -- can you let me know when I might expect to hear from them by email?
(08:19:35 PM) Patrick : sure thing, I cannot guarantee a time, as it will require some time to look into, but you should have an update within 12 to 24 hours for sure
(08:19:47 PM) Daniel Wintschel (email@example.com): OK great -- thanks again Patrick.
(08:20:30 PM) Patrick : anytime Daniel, all the best for now.
(08:30:15 PM) Patrick : take care
After contacting I just waited. I wanted to give them the benefit of the doubt. I knew I could try to start fixing this right away, write the code, change non-Canadian customers subscriptions to disable automatic tax calculation, write a bunch of code to back-bill and contact all the customers who had not been charged, but I wanted some answers. I wanted to know what went wrong, why they built this the way they did, and I wanted them to make some suggestion for a "best way" to address the issue.
I waited three days for a reply before I reached out to support a second time, on January 24th. What follows is the emailed transcript I received from Stripe Support after our chat ended (January 24th, 1422 hours PST):
This is Jerameel thank you for chatting with me earlier and I'm glad we were able to discuss the concern about Stripe Tax.
I wanted to send a copy of our conversation just in case you may need to reference it in the future. Feel free to get in touch with us if we can help with anything else.
— Chat started: 2022-01-24 09:52 PM UTC
(09:52:51 PM) Daniel Wintschel (firstname.lastname@example.org): Hey guys, -- I talked with support the other day (Saturday morning Pacific time) about a serious bug with the implementation of Stripe Tax... I've been waiting for a reply from that support chat being escalated -- and I really need a response.
(09:53:53 PM) Daniel Wintschel (email@example.com): I've now spent several hours trying to damage assess this and I need to know a) what went wrong on Stripe's side or b) if someone thinks that nothing is wrong -- and I need to figure out how to get it fixed ASAP.
(09:55:14 PM) Daniel Wintschel (firstname.lastname@example.org): Basically at this point after implementing and enabling Stripe Tax -- Stripe silently halted collections on a ton of my subscriptions leaving draft invoices for months... A damage assessment on my end now shows that I have a total amount due of redacted across redacted invoices for redacted customers...
(09:55:31 PM) Daniel Wintschel (email@example.com): That might not seem like a lot for a lot of your big customers but for me this is extremely significant.
(09:57:39 PM) *** Jerameel joined the chat ***
(09:57:50 PM) Jerameel: Hi there, thanks for getting in touch. My name is Jerameel from Stripe.
(09:58:36 PM) Jerameel: I'll be more than happy to assist you today.
(09:58:40 PM) Jerameel: I understand. Let me go ahead and look into it for you. Just give me a few minutes here.
(09:58:55 PM) Daniel Wintschel (firstname.lastname@example.org): Thanks Jerameel
(10:02:26 PM) Jerameel: Please bear with me for a few more minutes
(10:02:58 PM) Daniel Wintschel (email@example.com): Not a problem this is critical/urgent for me and I have no other priorities right now other than getting this resolved ASAP.
(10:07:37 PM) Jerameel: Upon checking, it appears that the concern has been escalated to our specialist who handles the concern for you. Here's what I'm goind to do, I'm going to make an immediate follow up so our specialist can reach out to you right away. The concern is now being look at by our specialist, however there is no specific timeframe I could provide for the response by our specialist but rest assure that I will now be raising an urgent follow up for you.
(10:09:32 PM) Daniel Wintschel (firstname.lastname@example.org): This is absolutely critical for my business... I have functionally 1/3 of my customers that I am going to have to back-bill for months of subscription fees and my churn rate is probably going to go through the roof. I can not stress how much this has f*cked over my business (with apologies for the expletive) but I really could use a timeframe. Is there something you can do to find out when I can expect to hear something?
(10:10:49 PM) Jerameel: By the way, I will be sending you an email as well after this chat for your future reference. Kindly wait for the email response from our specialist instead. Since the case is being handled by our specialist, I'm not able to provide a specific timeframe, however as I've mentioned I'll be raising this concern as an urgent matter so our specialist can reach out to you right away.
(10:12:15 PM) Daniel Wintschel (email@example.com): Thank you Jerameel. I feel really frustrated that there isn't a timeframe for this as I am literally sitting on my hands trying to figure out how to do this while potentially just waiting for my customers to evaporate as my cashflow is tanking.
(10:13:14 PM) Jerameel: I do undertand, I'll make sure to send this as an urgent request for you and I will be sending you an email right after this chat as proof that I raised this right away and that will also include the transcript of our conversation.
(10:13:24 PM) Daniel Wintschel (firstname.lastname@example.org): Thank you Jerameel.
(10:14:20 PM) Jerameel: No worries. I hope I was able to be of help.
(10:14:43 PM) Daniel Wintschel (email@example.com): Will be awaiting to hear from the specialist. Have a good day Jerameel.
(10:15:36 PM) Jerameel: Given that, will there be anyting else I can be of assistance?
(10:17:47 PM) Daniel Wintschel (firstname.lastname@example.org): That's all thank you.
(10:20:08 PM) Jerameel: Thank you for being so nice to me all throughout our conversation. You're very much welcome and thanks for your patience with me. Have a great day. (10:21:31 PM) *** Jerameel left the chat ***
The next day I finally received a response from someone in “priority support”, this email I received January 25th at 0830 PST:
Eoin from Stripe's priority support team, I'm going to be stepping in for Patrick here.
I've been in contact with our tax product engineers who have diagnosed the issue as follows:
Automatic tax was turned on for subscriptions where customers didn't have a recognised location. Without a recognised location, Stripe Tax can't calculate tax and this lead to the invoices staying in an unpaid state. I appreciate you didn't expect this behaviour but it is the default in cases where automatic tax is on without location . This occurred because the customer tax location was not validated during the migration to Stripe tax . You can turn on and off automatic tax on a per subscription basis. You should only turn on automatic tax for subscriptions where your customer has a valid location. In our migration guide we explain how to do this. To resolve this you will have to turn off automatic tax for all the subscriptions where you haven’t collected location information for the customer. Basically you have to turn off automatic tax for any unpaid subscriptions. Our team have taken feedback from this case to improve the API and will be exploring alternatives to make this more ergonomic/obvious in the future.
All the best, Eoin
This response didn’t help me feel any better at all, and if I’m honest, I felt fairly insulted. I can tell what the problem was, but I think there is a massive oversight in the implementation, and (probably because of lawyers), no one was going to say anything about whether or not this was a bug, or a total and massive miss on specifications and implementation at Stripe.
I replied with the following on January 25 at 1049 PST:
Thanks for getting back to me — but I want to let you know that this email does not resolve this to my satisfaction in the slightest.
I agree with most of what you said.
Many of the customers do not have enough information to compute tax obligations if I was registered to collect tax in countries other than Canada. I am not registered to collect tax anywhere but Canada - and therefore, the tax engine knows that I do not need any additional information for subscriptions that are US-based or based in other countries as I have no obligations to collect tax there.
Furthermore — while I appreciate that a zip code is required to automatically collect tax in the US, you’ll notice that for all subscriptions and customers where I am expecting to be able to collect tax (namely Canada) — I ensured all required data is present.
To silently fail without notifying the account owner in any way seems absolutely ludicrous to me as a software developer, and as a software developer of over 20 years, I would never shrug off what from the outside looks like an absolute and significant logical error with a response that functionally says “sorry man, you implemented it wrong, we’re not doing anything about this.”
In your documentation on “Handling unrecognized locations” — it does not say “we’ll just stop billing your customer and not tell you about it”.
You also say in your email: "You should only turn on automatic tax for subscriptions where your customer has a valid location.” — if this were true in the absolute sense (e.g. we will literally stop collecting your revenue and not tell you about it) — this should be in a giant, red, heading somewhere as that is most definitely not what I would expect follows any kind of rule of least surprise. Not only that, but I did search for that phrase "You should only turn on automatic tax for subscriptions where your customer has a valid location” and I can’t see anything specific in the documentation that says this, let alone what the consequences will be if you fail to follow this instruction.
Perhaps I could see setting “not_collecting” flag and, again, finding some way to notify the account owner that something is wrong or missing.
But — I feel like all of this is completely besides the point, because the tax engine has all the data it needs to correctly determine all my tax obligations. Maybe, if I added a registration to collect tax in Alabama or something, I could see that subscriptions in Alabama get flagged as needing more info — but there was no reason whatsoever for my customers subscriptions to have collection suspended based on the address data present in their account.
I would like a further follow-up, preferably escalated to a senior developer or a manager, as I’d like more information, and I’d also like to figure out what can be done to help compensate for the actual damages.
I’m not trying to be unreasonable, but I also fail to see how this is a “sorry man, you implemented it wrong, we’re not doing anything about this.”
In this email I included two screenshots from Stripe's web site documentation, in particular the section on “Handling Unrecognized Locations”. Here is what that page looked like when I emailed the screenshot to support (Jan 25, 2022)
And here's what it looks like today (March 2)
In the mean time, I had also been reaching out to, who best I can tell, was the product manager or product lead for Stripe Tax because I had her email address and contact information from previously discussing Stripe Tax with her.
In the end, I received this email from her on January 31st at 1947 hours PST:
The team has made updates to our docs to make this more clear and they are looking into a synchronous alert. https://stripe.com/docs/tax/subscriptions/migrate#subs https://stripe.com/docs/tax/subscriptions#handling-location-validation https://stripe.com/docs/tax/customer-locations#handling-errors
It looks like you were able to back bill the invoices from what I can see on my end.
Best, name redacted
My email that I sent to Eoin on January 25th went completely ignored for a full 14 days, until I received this reply:
Apologies for the delay, I can see product lead name redacted reached out about updates to our documentation here. As product lead name redacted outlined we're looking at different ways to create such an alert now to prevent this happening without warning in future. I apologise for the difficulty here but happy to see you've successfully back billed your customers.
All the best, Eoin
The summary on my end was basically a royal “screw you” wrapped up in a bit more flowery language, with absolutely zero acknowledgement that anything may have been implemented incorrectly, and deflected all responsibility.
I wasn’t going to even write about any of this, until yesterday afternoon (March 1st), I received the following (what looked like an automated) email from Stripe Support:
I’m Jennifer and I work on Billing/Tax at Stripe. I’m writing to you because we noticed that multiple invoices for your automatic tax subscriptions have been failing on finalization due to an unrecognized customer location —a required component of Stripe Tax. You can see the full list of the failed subscriptions on your Dashboard:
I wanted to let you know how you can resolve these failures, and to get your thoughts on a solution we’re proposing which would resolve the issue earlier in the subscription update process.
We currently validate the customer location at the invoice finalization stage, which is why these failures are occurring. The best way to respond to these failures at the moment is to listen for the invoice.finalization_failed webhook to detect any unrecognized customer locations, and then correct the customer’s address accordingly, as described in our documentation .
What we’d like to do:
We’re considering modifying subscription behavior so that customer location validation takes place at the subscription update stage. This would mean that, when migrating a subscription from manual to automatic tax  with Stripe Tax, an unrecognized customer location would cause the subscription update request to fail, allowing you to correct the customer’s address before any invoices are created.
To help us understand how well this would work for your business, we’d appreciate it if you could answer the following questions:
Invoice finalization: Does your integration currently listen for the invoice.finalization_failed webhook and respond to these failures? If not, can you tell us if this is the first time you’ve been made aware of this issue? Subscription migration: Does your integration rely on the current behavior which allows a subscription to be migrated to have automatic tax enabled when the customer has an invalid location?
We’d really appreciate any feedback you could give us, and of course, please let me know if you have any questions.
The Stripe Billing team
To me, the fact I am receiving this email means that this clearly affected more than just myself as a customer, and it feels like there is a lot of internal dialog at Stripe about this. What really sent me straight over the edge of my already frustrated seat was that the link in the email to the invoices that have allegedly failed to process is 404 (not found) and there is still no notice on the dashboard (that I can see or find) that links to any such failed invoices.
I guess I just feel I expected a lot more. Some sort of an apology? Here’s a year or two of free payment processing? Thanks for pointing out our massive engineering failure?
Maybe this rant will make the Stripe Tax and developer people all mad at me so they never hire me if I applied for a job there. Maybe their internal Slack channels are full of mocking stories about “that stupid customer who screwed up their Stripe tax implementation”. Maybe they’re full of “Holy shit I can’t believe we didn’t anticipate this”.
Who knows? All I know is, if I made what I considered to be an engineering error of this magnitutde, I hope I’d have the integrity to make it right in a meaningful way to the customer, instead of blaming the customer for reading the documentation wrong.
Or maybe Stripe made no mistakes, and I am just the customer who read the documentation wrong so "sorry, tough luck bub" to me.
Usually, I would spend a lot more time polishing the writing of a piece like this but, truth be told, even documenting this much has been exhausting. So if you’re reading, I hope you “enjoyed” it.
If you have any thoughts on this, or want to contact me about it please reach out -- you can find my email address in the chat transcript above, or a simple google search of my full name will provide you with plenty of ways in which you can get ahold of me.
I'd love to know, particularly from software engineers, if you feel like this situation is more a failure on my part, or the failure on the part of Stripe's Tax implementation.
You did a good job describing that urge to right the wrong even if your effort is disproportionate to the benefit you expect to receive. I know exactly what you're talking about.
It reminds me a bit of how a honey bee will sacrifice its entire life to incentivize a larger animal to respect the hive (bees die after they sting). It may not be the best decision for the bee personally, but it's a pro-social move that ensures the well being of its friends and family.