Tax: VAT, GST, Sales Tax, and Withholding

Tax is where “just add a percentage” goes to die. It is the most localisation-heavy area of an ERP and the one most likely to be outsourced to a specialist engine.

The tax families

Family How it works Where
VAT / GST Charged at every stage; businesses reclaim input tax; the consumer bears it EU, UK, India, Australia, Canada (GST/HST), Bangladesh (Mushak), most of the world
US Sales & Use Tax Charged only at final retail sale; no input credit; thousands of jurisdictions USA
Withholding tax The payer deducts and remits on behalf of the payee India (TDS), Bangladesh, most of Asia/Africa/LatAm, US 1099 backup
Excise / duty Per-unit on specific goods (alcohol, fuel, tobacco) Global
Customs duty On imports, based on HS code, origin, and value Global
Digital services tax On cross-border digital sales Growing

VAT mechanics

Buy raw material 1,000 + 150 input VAT     → you pay supplier 1,150
Sell finished goods 2,000 + 300 output VAT → customer pays you 2,300

Remit to tax authority: 300 output − 150 input = 150

Postings:

Purchase:
  Inventory              Dr 1,000
  Input VAT receivable   Dr   150       ← an asset, you'll reclaim it
    Accounts payable        Cr 1,150

Sale:
  Accounts receivable    Dr 2,300
    Revenue                 Cr 2,000
    Output VAT payable      Cr   300    ← a liability, you owe it

Period end:
  Output VAT payable     Dr   300
    Input VAT receivable    Cr   150
    VAT payable to authority Cr  150

The key insight: VAT is never revenue or expense for a registered business. It flows through the balance sheet. If VAT ever lands in your P&L, something is wrong — except where input VAT is non-recoverable (entertainment, some vehicles, exempt activities), in which case it becomes part of the cost.

Tax codes

The central configuration object. A tax code bundles: rate, GL accounts, reporting box, and rules.

Code  Description                Rate   Type    Deductible  Reporting box
V0    Domestic purchase 0%       0%     Input   Yes         B7
V1    Domestic purchase standard 15%    Input   Yes         B7 / B4
V2    Domestic purchase reduced  7.5%   Input   Yes         B7
VE    EU acquisition (reverse)   20%    Both    Yes         B2 / B4
VN    Non-deductible             15%    Input   No          —
A0    Domestic sale exempt       0%     Output  —           B6
A1    Domestic sale standard     15%    Output  —           B1
AE    Export 0-rated             0%     Output  —           B6 / B8

Every document line carries a tax code. Getting it right is 90% of tax compliance.

Tax determination

The engine picks the code from a matrix. Inputs:

  Ship-from country/region        (where goods leave)
  Ship-to country/region          (where goods arrive)
  Bill-to country                 (who is invoiced)
  Customer tax classification     (registered / exempt / government / export)
  Material tax classification     (standard / reduced / exempt / excise)
  Transaction type                (sale / purchase / service / asset)
  Registration status of both parties
  Date                            (rates change)
  ─────────────────────────────────────────────────
  → Tax code, rate, and reporting treatment

Never hardcode a rate. Rates change, sometimes with weeks’ notice, and always with an effective date. The rate must be a dated master data lookup.

The hard cases

Reverse charge

The buyer accounts for the tax instead of the seller. Used for cross-border B2B services and some domestic anti-fraud regimes (construction, electronics, carbon credits).

Reverse charge purchase, 10,000 @ 20%:
  Expense                Dr 10,000
  Input VAT              Dr  2,000       ← you claim it
    Output VAT              Cr  2,000    ← and you owe it
    Accounts payable        Cr 10,000

Net cash effect: zero. Both sides must appear on the return.

Your posting logic must generate both tax lines from a single tax code. This is a distinct code type, not a rate of zero.

Place of supply

Which country’s tax applies? Rules differ for goods vs services, B2B vs B2C, digital vs physical. EU B2C digital services are taxed where the customer is, which is why the OSS/MOSS scheme exists. Getting this wrong means registering and paying in the wrong country.

Triangulation / chain transactions

A sells to B sells to C, goods move directly A→C, across three countries. Which leg is the zero-rated intra-community supply? This has its own simplification rules and its own invoice wording requirements.

US sales tax nexus

After South Dakota v. Wayfair (2018), economic nexus means you owe sales tax in a state once you cross a revenue or transaction threshold there — no physical presence needed. With 13,000+ taxing jurisdictions (state, county, city, special districts) and address-level rate determination, nobody builds this themselves. Use Avalara, Vertex, or Sovos.

Partial exemption

If a business makes both taxable and exempt supplies (banks, insurers, healthcare, education), only a proportion of input VAT is recoverable. The proportion is calculated annually with an adjustment. This is genuinely complex and requires dedicated functionality.

Tax point / time of supply

When is the tax due? Options by jurisdiction: invoice date, delivery date, payment date, or the earlier/later of these. Cash accounting schemes shift the tax point to payment. This is why document_date matters separately from posting_date.

E-invoicing and real-time reporting

The biggest change in tax technology. Governments increasingly require invoices to be transmitted to (and often cleared by) a government platform before or as they are issued.

Country System Model
Brazil NF-e / NFS-e Clearance — government authorises before goods can ship
Mexico CFDI Clearance via authorised providers (PAC)
Italy SdI Clearance for all domestic B2B/B2C
India IRP + e-way bill Clearance — Invoice Registration Number + QR code required
Saudi Arabia ZATCA Fatoora Phased clearance with cryptographic stamps
Poland KSeF Clearance
Hungary RTIR Real-time reporting
Turkey e-Fatura Clearance
Chile, Peru, Colombia Various Clearance
EU ViDA Digital Reporting Requirements rolling out through the late 2020s

Implications for developers:

  • Invoice issuance becomes a synchronous call to a government API that can fail, time out, or reject.
  • You need retry logic, a queue, and a status machine (pending → submitted → cleared → rejected → cancelled).
  • The invoice may not be legally valid until cleared — so you can’t print or send it yet.
  • Cryptographic signing, QR codes, and specific XML schemas per country.
  • Cancellation windows are limited (often 24–72 hours); after that you must issue a credit note.
  • Design rule: never make document posting depend on the external call succeeding. Post, then submit asynchronously, then track clearance status. Blocking the ledger on a government API’s uptime is a bad day waiting to happen.

Withholding tax

The payer deducts tax from the payment and remits it.

Vendor invoice 100,000, WHT 10%:
  Expense                  Dr 100,000
    Accounts payable          Cr  90,000
    WHT payable               Cr  10,000

Complexity:

  • Rate depends on vendor type (company/individual/non-resident), service type, and treaty status
  • Thresholds — no withholding below X per transaction or per year, then retroactive
  • Certificates must be issued to the vendor (they claim credit for it)
  • Separate periodic returns
  • Double-tax treaty rates require documentation (tax residency certificate)

India’s TDS, Bangladesh’s AIT/VDS, and similar regimes are deep localisation. Do not underestimate them.

Build vs buy

  Build in ERP Buy a tax engine
Single country, VAT, simple products ✅ Build Overkill
US sales tax ❌ Never build ✅ Avalara / Vertex / Sovos
Multi-country VAT with e-invoicing Possible but heavy ✅ Usually buy
Withholding tax, one country ✅ Build (localisation) —

Tax engines are called synchronously during pricing to return the tax amount per line. Latency matters — cache aggressively for repeated address/product combinations, and always have a fallback rate so an engine outage doesn’t stop order entry.

Reporting

Standard outputs the ERP must produce:

  • VAT/GST return — box-by-box, per registration, per period
  • EC Sales List / recapitulative statement (EU)
  • Intrastat — statistical declaration of intra-EU goods movements, by commodity code and weight
  • SAF-T — Standard Audit File for Tax; a prescribed XML dump of the full ledger. Required in Portugal, Poland, Norway, Lithuania, Romania and spreading
  • Withholding certificates and returns
  • Reconciliation: tax GL account balance = sum of tax line items = return total. Any mismatch is an audit finding.

Developer checklist

  • Tax code on every line, no exceptions (0% is a code, not a blank)
  • Rates are dated master data, never constants
  • Tax is computed at line level and stored, never recalculated on display
  • Tax base amount stored alongside the tax amount
  • Rounding rule per jurisdiction (line-level vs invoice-level rounding differs by country)
  • Reverse charge produces two tax lines
  • Non-deductible input tax is added to the cost, not the tax account
  • Tax registration number of both parties captured on the document
  • E-invoicing submission is asynchronous with a retry queue and a status machine
  • Credit notes reference the original invoice number and reverse the same tax codes
  • Tax GL accounts reconcile to the return, automatically, every period

Next