For a while, our pricing page advertised $79 a month for the Professional plan. Stripe charged €79. Nobody noticed, because both numbers were 79.
Three places to store one fact
A price seems like a single fact. In practice it lived in three:
- Stripe, which decides what a card is actually charged.
- Our database, which the pricing page reads.
- The page itself, where some figures were typed directly into the markup.
Any two of those can agree while the third quietly disagrees. Ours managed all three failure modes at once. Three plans were stored as dollars and charged as euros — about eight percent more than the page promised. Another set was genuinely priced in dollars while the company banks in euros. And a comparison table further down the page advertised a tier at a price that had never existed in either system.
We also found the table promising 100GB of storage and 25 team members on a plan that actually granted 1GB and one seat — and those limits are enforced, so anyone buying on that promise would have hit a wall immediately.
None of this was reported by a customer. It was found by writing something that compares the two systems and refuses to agree with itself.
Letting Stripe own the number
The fix was not to sync more carefully. It was to decide which system owns each fact and make everything else derive from it.
Stripe owns what you are charged. Our database now matches it exactly — every plan in euros, every price tax-exclusive, checked daily by a job that fails if the two ever drift apart again. A mismatch now breaks a build rather than a customer’s invoice.
The page owns nothing. Every figure it shows is read from the plan record, including the quotas in that comparison table. There is no longer anywhere to type a price.
Tax, properly
While we were in there we fixed something with a legal dimension rather than a cosmetic one: our checkout collected no VAT information at all.
For a business buying software across the EU, that matters. A company with a valid VAT number should be reverse-charged — they account for the VAT themselves, and our invoice must record their number. Without a way to enter it, every business customer was treated as a private individual.
Checkout now asks for a VAT number, validates it, and applies the correct treatment. A Lithuanian customer pays our domestic rate. An EU business with a valid number is reverse-charged and pays no VAT to us. The tax logic is Stripe’s to maintain, not ours — we deliberately do not keep a second table of rates, because a second table is just the same bug waiting in a different column.
One gap remains and we would rather say so: consumers elsewhere in the EU are not yet charged their local rate, which requires a registration we have not completed. Business customers — almost all of you — are handled correctly today.
The part that nearly slipped through
After aligning the database with Stripe, our comparison job reported no drift. The
pricing page still said $49.
The number was right. The currency symbol was typed into the page, and no amount of comparing two systems could see a third. Everything that displays money now formats it from the same record that Stripe charges against.
Data agreeing with data is not the same as the page telling the truth.



