What it takes for a small German company to sell software outside Germany (and why we said no to most of the world, for now)
· Christoph Heuwieser
From the start, a4sx had one simple rule: buyers need a billing address in the EU or the EEA. The reason was tax, not ambition. As a German company we can report VAT on sales to consumers in other EU countries through the EU's One-Stop-Shop (OSS), with one return filed at home. Outside the EU, selling to consumers can mean a foreign VAT or GST registration, and we had decided not to take any on. Buyers from outside were refused before checkout, and sellers had to be established in the EEA to get paid.
Then we asked the obvious question: shouldn't a digital marketplace be open worldwide? Two days of scope changes, review rounds and rewritten Terms followed. None of it is our product, and all of it had to be settled before we could sell one more item abroad. Here is what we ran into and what we decided. It is not legal or tax advice. Where a question is still open, our tax advisor is checking it.
The zig-zag
Worldwide. The first plan sorted countries into tiers by their tax-registration thresholds: the UK, Switzerland, Australia, New Zealand, Singapore, South Korea, the UAE, Taiwan, Hong Kong, Canada, Japan, India and more. Many of these countries have no threshold at all for digital services sold to consumers. In the UK, for example, registration is due from the first consumer sale.
EU + US. The same evening we narrowed it down: focus on the most important markets, the US and the EU, and leave the rest out for now. The first US stage was to be businesses only, with five launch conditions: a required EIN, our own per-state tax counters, net EUR prices, a sanctions name screen, and new legal texts.
EEA + US. The next morning we turned it around: restrict sellers, and leave buyers open wherever we can handle the tax. That opened the US to consumers as well as businesses, made the EIN optional, and kept Norway, Iceland and Liechtenstein open behind threshold counters.
EU + US, again. A few hours later those three countries went on the refusal list. Our buyer scope is now the 27 EU countries plus the US, and the US part sits behind a switch that is not on yet. Sellers stay EEA-only.
The OSS covers the EU, not the EEA
It's tempting to think of the EEA as "the EU plus a bit". For VAT it isn't. The OSS covers EU consumers only. Norway, Iceland and Liechtenstein each have their own registration rules and thresholds: Norway's VOEC scheme from NOK 50,000, Iceland from ISK 2 million, and Liechtenstein under the Swiss rule of CHF 100,000 in worldwide turnover (figures our tax advisor is confirming). For a few hours we planned counters that would stop sales well before any of those. Then we simply refused buyers from the three countries. They are small markets.
US sales tax is fifty questions
There is no single US sales tax. Each state sets its own economic-nexus threshold, mostly $100,000 in sales or 200 transactions a year, and some $500,000. Whether digital goods are taxable at all also varies from state to state. We built our own per-state counters, on calendar years. They alert at 50 % of a threshold and block sales at 80 %, well before a registration would be due.
Counters sound simple. They weren't. With subscriptions the first invoice is charged later, by webhook, and Stripe's invoice.paid event can arrive before checkout.session.completed, so a check before payment alone can oversell. We now reserve the first invoice per market and lock the market while a sale is booked. SEPA debits and other slow methods can take days, so a 24-hour reservation let late payments book unchecked; those now hold for seven days, and anything slower is a known edge.
US auto-renewal laws
A number of US states have auto-renewal laws with their own rules for how subscriptions are sold and cancelled. That needs its own subscription flow, and until we have built it, US buyers will get marketplace items only, not subscriptions.
EIN: required or optional?
For US business buyers we went back and forth on the Employer Identification Number. Requiring it protects us if a "business" later turns out to be a consumer with a consumer's claims. Making it optional lets sole proprietors buy without having to give their Social Security Number. We decided on optional, "if the business has one", and every text that had already been approved had to be re-aligned.
The handling has its own traps. We never store the number in clear, and we compare a keyed fingerprint of the full number: matching on the last four digits once reused an old checkout after a buyer corrected their EIN. We attach it to Stripe only after payment, so abandoned checkouts leave no customer records holding an EIN.
Sanctions, and why we dropped the name screen
We are an EU company, so we work with the EU and UN sanctions lists. The first design also ran a fuzzy name screen on business buyers. When we tested it, it flagged 72 % of common Arabic given name and surname pairs, against 0.38 % of Western names, plus "David Davis"-style false hits. It also ran after payment, so a false hit meant taking someone's money and then holding their order. We didn't think we could run that fairly, and we dropped it. Sanctions are now a country block: if a buyer's declared or billing country is excluded under the EU or UN lists, we refuse the sale.
What Stripe won't do for you
Three things surprised us:
- Checkout's allowed_countries restricts the shipping address, not the billing country. Software has nothing to ship.
- The invoice memo is fixed when the Checkout session is created. A buyer who declared the US but paid with a German address got the wrong invoice wording. Our fix: create the invoice after payment, from the final billing country.
- Geo rules in Radar need Radar for Fraud Teams, which we don't use.
So the country checks live in our own code, before checkout and again at fulfilment.
Invoice wording, in German
An invoice for a sale outside the EU needs the right note. Ours reads "Nicht im Inland steuerbar (§ 3a UStG)", roughly "not taxable in Germany". Which paragraph of § 3a applies to consumers and which to businesses is a question for our tax advisor, as is the matching line on the German VAT return (Kennzahl 45, which covers non-taxable foreign sales).
Terms re-acceptance churn
Each change of region touched the same set of texts: § 5 of the Terms, the purchase dialog, a sentence on the Stripe payment page, the help center, the data processing agreement and the privacy policy. Every sentence a buyer sees needs sign-off on its exact wording. So that users don't have to re-accept the Terms every time we change our minds, we stage each Terms version behind a switch. Users re-accept once, when it actually goes live.
The 15-day seller notice
Sellers had their own list. Stripe Connect can't pay out to Iceland. German platform reporting (DAC7) needs complete seller data. Withholding tax for sellers outside Germany is a risk we have accepted at our current revenue, to revisit once revenue is meaningful.
Then we changed the payouts. We decided on monthly payouts with a €20 minimum, but our published seller Terms said weekly. Under the EU's platform-to-business (P2B) Regulation, business users must get at least 15 days' notice of a terms change, or the change is void for them.
Our first draft held every seller's earned payouts until they re-accepted the new terms. Review stopped it. Holding money that is already owed, as leverage, is coercive. It undercuts the seller's right to leave instead of accepting, and it risks default interest and unfair-terms problems under German law. What we agreed instead: an email at least 15 days ahead, the new rule applies from that date, no payout hold, and existing self-billing consents stay valid. A seller who doesn't agree can leave before then, and what they have already earned is paid out as before.
Even that took several review rounds, over free sellers (they get payouts too), sellers who join during the notice window, sellers without an email address, test accounts, and suspended-then-reinstated sellers. We don't store a language per user, so sellers with workspaces in Germany, Austria or Liechtenstein get the German notice and everyone else gets English.
What we learned
- Scope by tax regime, not by map. "EU" and "EEA" are different answers for VAT, and "the US" is fifty-odd answers.
- Your payment provider is not your compliance layer. Check what each setting really restricts before you rely on it.
- Test a screen on real names before you trust it, and run it before payment. A check that is wrong for whole groups of people, after their money is taken, is not one we want to run.
- Every scope change costs text. Count the legal texts a change touches before you make it, and version them so customers accept once.
- Budget for review rounds. Ours caught double counting under concurrency, threshold checks that missed the current sale, the wrong refusal text for a country, and a refund that never happened on a held subscription.
- Never use earned money as leverage. Changing terms for business users has a clock. Plan the notice in.
- Keep a log. This post exists because we wrote down every decision as we made it.
So, for now, we said no to most of the world. Not because those markets don't matter, but because each one is its own registration, threshold, invoice note and set of texts. The rest stays closed until our tax advisor's answers are in.