DField SolutionsLoading · Töltődik
Skip to content

We see the same mistake every quarter at SaaS audits. The team enabled Stripe Tax, ticked Hungary, and assumed the box now says 'compliant'. It does not. Stripe Tax computes the tax. The Hungarian-law-compliant invoice and the NAV reporting are still your problem. This post is the chain we ship for clients selling SaaS into and from Hungary.

Disclaimer: laws are laws and your accountant approves the final spec. Everything below is engineering shape. The numbers (27% standard rate, B2B reverse charge, MOSS / OSS thresholds) are from current Hungarian and EU rules as of 2026-04-26 · check before go-live.

Step 0 · what Stripe Tax actually does

Stripe Tax determines whether a transaction is taxable, at what rate, where, and stamps that on the invoice. It also covers thresholds (EU OSS, US economic nexus). It does NOT issue Hungarian e-invoices, file with NAV, or generate the legally required invoice fields under Hungarian law (Act CXXVII of 2007 §169). You still need a billing layer that can.

Step 1 · register where you owe tax

  • Resident Hungarian SaaS: standard NAV registration plus VAT registration. Above the local threshold you charge 27% domestic and use OSS for cross-EU B2C.
  • Non-resident selling B2C into Hungary: register for OSS in your home state, NOT Hungary directly. Stripe Tax filters and applies the right rate.
  • Selling B2B into Hungary from another EU state: reverse charge applies if the buyer has a valid HU VAT number. Verify via VIES on capture, store the number on the invoice.
  • Selling to non-EU customers: rules vary, Stripe Tax handles US states and most major destinations; double-check edge geographies before launch.

Step 2 · the Stripe Tax wiring

Use `automatic_tax: { enabled: true }` on every Subscription and Invoice. Pass the right address fields on the Customer · billing address is the source of truth for VAT location. For B2B EU sales, capture and pass the buyer's `tax_ids` · Stripe Tax then applies reverse charge automatically and stamps the buyer's VAT ID on the invoice.

import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET!);

await stripe.customers.update(customerId, {
  address: { country: "HU", postal_code: "1051", city: "Budapest", line1: "..." },
  tax_id_data: vatNumber
    ? [{ type: "eu_vat", value: vatNumber }]
    : undefined,
});

await stripe.subscriptions.create({
  customer: customerId,
  items: [{ price: priceId }],
  automatic_tax: { enabled: true },
  collection_method: "charge_automatically",
});

Step 3 · validate the VAT number, not just record it

A Hungarian VAT number on a customer record is worth nothing if you have not validated it. NAV publishes a SOAP / REST endpoint, the EU offers VIES, and Stripe will verify EU VAT IDs you attach to a customer. Do all three at the right moments: validate at signup, re-validate periodically, and re-check before issuing a B2B reverse-charge invoice. Cache the result with a short TTL · VIES rate-limits hard.

Step 4 · the Hungarian-compliant invoice

Hungarian law (Act CXXVII of 2007) requires fields Stripe's default invoice does not include in the right format · sequential number under a registered range, supplier and buyer tax numbers, exact issue and supply dates in HU format, line-item VAT rate, the VAT amount in HUF if billing in another currency, and a few more. We generate the invoice in our billing layer and reference Stripe's invoice as the underlying transaction.

  • Sequential numbering: register your invoice prefix with NAV (`SZAMLA-2026-` etc), persist the next number in a transactional counter, never reuse.
  • Currency: if you bill in EUR or USD, also show the HUF equivalent at the MNB middle rate of the supply date. Persist that rate, do not look it up at print time.
  • Reverse charge B2B: include the legend 'fordított adózás · reverse charge' and the buyer's VAT ID. Tax rate and amount on the line are zero in this case.
  • Storno (cancellation) and modification invoices: they are first-class objects, not 'just delete and re-issue'. NAV cares about the chain.
  • PDF + structured XML: store both. The XML is what gets reported.

Hungary requires every B2B and B2C invoice issued by a Hungarian-registered taxpayer to be reported to the NAV Online Invoice system within minutes of issue. v3 is mandatory in 2026. The integration is XML over REST with a signed token; failure responses come back with explicit error codes. We retry on transient failures, surface persistent ones in our ops dashboard, and never block the customer-facing flow on NAV being slow.

// pseudo-code for the NAV submission flow
async function reportToNav(invoiceId: string) {
  const xml = await renderInvoiceXml(invoiceId);
  const token = await navTokenExchange();
  const r = await navClient.manageInvoice({
    operation: "CREATE",
    invoice: xml,
    token,
  });
  if (r.result.funcCode === "OK") {
    await markReported(invoiceId, r.transactionId);
  } else {
    await enqueueRetry(invoiceId, r.result);
  }
}

Step 6 · reverse charge code path · the bug factory

Most teams ship the domestic flow correctly and then break on a Polish or German B2B sale. Reverse charge means: the buyer pays the VAT in their own country, you charge zero, your invoice carries the legend and the buyer's VAT ID. Stripe Tax does the calculation if `tax_ids` is set. Your billing layer must render the correct legend, your accounting code must classify the transaction as reverse-charge for the recapitulative statement (A60 in HU).

Step 7 · the recapitulative statement (A60)

Quarterly, Hungarian VAT-registered sellers must file an A60 listing all intra-EU B2B sales with VAT IDs and amounts. Stripe Tax exports a file you can use as the source. Your accountant needs the data in a format their system reads · do this once, automate it, do not do it by hand at quarter end.

Step 8 · refunds, credits, partial refunds

  • A refund needs a credit note (storno or modification invoice). NAV reporting is required for it too.
  • Partial refunds need a modification invoice referencing the original. Issuing two unrelated 'negative' invoices is wrong.
  • Subscription mid-period upgrades: the proration credit / debit lines must each appear correctly with VAT. Stripe handles the math; the invoice template must match.
  • Disputes / chargebacks: the original invoice stays valid. The accounting movement is separate. Do not 'fix' it by issuing a fake credit note.

Common pitfalls

  • Setting `automatic_tax` only on Subscription, not on one-off Invoices. Always both.
  • Trusting the customer-entered VAT ID without verifying. The fines are on you, not on them.
  • Issuing the Stripe-rendered PDF as the customer's official invoice. It is not. Generate your own.
  • Forgetting the HUF equivalent on a foreign-currency invoice. NAV rejects it.
  • Reporting the invoice to NAV before persisting your sequence number atomically. Two invoices with the same number is a real audit finding.
  • Skipping the recapitulative statement for low-volume EU B2B. Filing zero is not the same as not filing.

If your accountant tells you 'just send me a CSV at quarter-end', you have a system-design opportunity. The same data plus a `nav_status` column plus a downloadable A60 saves a day of finger-pointing every quarter.

The shape that survives audit is: Stripe Tax for calculation, an in-house billing service for legally compliant invoices, an async NAV reporter behind a queue, a verified VAT-ID flow on signup and renewal, and a quarterly export the accountant can ingest. Build that once, treat it as a system, do not retrofit it on the night before a tax inspection.

ShareXLinkedIn#
Dezso Mezo
By

Dezso Mezo

Founder, DField Solutions

I've shipped production products from fintech to creator-tooling · for startups and enterprises, from Budapest to San Francisco.

Keep reading
RELATED PROJECTS
Let's talk

Would rather build together?

Let's talk about your project. 30 minutes, no strings.