On a PDF invoice, "no VAT charged" looks like one thing: a zero in the tax column. In EN 16931 it is at least four different things — reverse charge, intra-community supply, export, out of scope — each with its own category code, its own rule family, and its own way of rejecting your XML. Map them all to "0%" in your invoicing model and the validator will teach you the difference one error code at a time.

This article walks the category codes as a developer needs them: what each letter means, the rule cluster that fires per category, and the three edge cases — AE, K, and O — that account for most of the failures we see. If your one-cent problems are arithmetic rather than semantic, that's a different article (the BR-CO chain and BR-DEC decimal rules); this one is about picking the right letter.

The codes

Every invoice line (BT-151), document-level allowance (BT-95) and charge (BT-102) carries a VAT category code from the UNCL5305 subset that EN 16931 and Peppol BIS 3.0 allow:

Code Meaning Rate in XML Typical case
S Standard rated > 0 Plain domestic sale (19%, 21%, 27%…)
Z Zero rated 0 Goods your national law taxes at 0%
E Exempt from tax 0 Domestic exemptions (education, health, insurance…)
AE VAT reverse charge 0 Buyer accounts for the VAT (e.g. cross-border B2B services, §13b UStG cases)
K Intra-community supply 0 B2B goods/services to another EU member state, VAT-exempt
G Free export item 0 Export outside the EU
O Services outside scope of tax none The transaction isn't subject to VAT at all
L / M / B IGIC (Canary Islands) / IPSI (Ceuta & Melilla) / split payment (Italy) varies Regional/national special regimes

One thing worth saying plainly: choosing between these is tax determination, and that's your (or your customer's accountant's) call — whether a given Berlin-to-Vienna consulting gig is AE or K is a question of VAT law, not of XML. What the standard does pin down, and what a validator can enforce, is that once you've picked a letter, the rest of the document must be consistent with it. That consistency is where integrations break.

One breakdown per category, and a rule cluster per letter

The VAT breakdown (BG-23, cac:TaxTotal/cac:TaxSubtotal in UBL) groups the invoice by category — and, for S, by rate. Every invoice needs at least one breakdown group (BR-CO-18), lines with a given category need a matching group, and each group's taxable amount (BT-116) must equal the sum of line nets minus allowances plus charges for that category — the category-level analogue of BR-CO-10. Each group's tax amount (BT-117) then rolls up into BT-110 and the totals chain checked by BR-CO-15 and BR-CO-16.

The elegant part — and the reason this is learnable rather than 60 arbitrary rules — is that every category gets the same cluster shape, numbered the same way. For a category X: BR-X-01 (breakdown group must exist), BR-X-02..04 (which party identifiers are required — or forbidden), BR-X-05..07 (what the rate must be), BR-X-08 (taxable amount sum), BR-X-09 (tax amount), BR-X-10 (exemption reason required — or forbidden). Learn the shape once and every error code becomes self-locating.

The clusters differ exactly where the business cases differ. Three of them are worth knowing by heart.

Edge case 1: reverse charge (AE) — zero, but never empty

Reverse charge means the buyer accounts for the VAT. The XML consequences:

  • The rate is 0, not absent. BR-AE-05: an AE line's VAT rate (BT-152) shall be 0 (zero) — omitting cbc:Percent is a different failure than writing 0.
  • Both parties must be identifiable. BR-AE-02 requires a seller VAT identifier (BT-31), tax registration (BT-32) and/or tax representative ID (BT-63), and a buyer VAT identifier (BT-48) and/or buyer legal registration identifier (BT-47). Reverse charge shifts the liability to the buyer, so the document must say who the buyer is, fiscally.
  • The exemption reason is mandatory. BR-AE-10: the AE breakdown group needs an exemption reason code (BT-121) meaning "Reverse charge" — in the VATEX list that's the code VATEX-EU-AE — or equivalent free text in BT-120.
  • BR-AE-09: the category tax amount is 0. Yes, you state a taxable amount and a zero tax on it.

A correct AE breakdown group in UBL:

<cac:TaxTotal>
  <cbc:TaxAmount currencyID="EUR">0.00</cbc:TaxAmount>
  <cac:TaxSubtotal>
    <cbc:TaxableAmount currencyID="EUR">2500.00</cbc:TaxableAmount>
    <cbc:TaxAmount currencyID="EUR">0.00</cbc:TaxAmount>
    <cac:TaxCategory>
      <cbc:ID>AE</cbc:ID>
      <cbc:Percent>0</cbc:Percent>
      <cbc:TaxExemptionReasonCode>VATEX-EU-AE</cbc:TaxExemptionReasonCode>
      <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
    </cac:TaxCategory>
  </cac:TaxSubtotal>
</cac:TaxTotal>

Edge case 2: intra-community supply (K) — the two rules nobody expects

K looks like AE's twin — rate 0, tax 0, exemption reason required (BR-IC-10, code VATEX-EU-IC) — but its identifier rule is stricter in one direction: BR-IC-02 demands the buyer VAT identifier (BT-48) specifically. A buyer legal registration number is not an accepted substitute the way it is for AE, which mirrors the tax law: the intra-community exemption hinges on the buyer being VAT-registered in another member state. (This is also why checking the counterparty's number against VIES before invoicing is worth automating — our free VIES check tool does it in the browser.)

Then come the two rules that surprise every first-time integrator, because they reach outside the tax data entirely:

  • BR-IC-11: an invoice with a K breakdown must state the actual delivery date (BT-72) or an invoicing period (BG-14).
  • BR-IC-12: it must state the deliver-to country code (BT-80).

Both fields live in the delivery group most invoice generators skip when there's no physical shipment. If your K invoices fail and the error names BT-72 or BT-80, this is why: the exemption is only assessable if the document says where and when the supply happened.

Edge case 3: out of scope (O) — the exclusive category

O ("services outside scope of tax") is not another zero — it says VAT law doesn't apply to this transaction at all. The rule cluster is accordingly inverted:

  • No rate, period. BR-O-05: an O line shall not contain a VAT rate. Writing <cbc:Percent>0</cbc:Percent> — correct for every other zero case — is an error here.
  • No VAT identifiers. BR-O-02: the invoice shall not contain a seller VAT identifier (BT-31), tax representative ID (BT-63) or buyer VAT identifier (BT-48). If your XML builder unconditionally emits the seller's VAT number, every O invoice it produces is invalid.
  • No mixing. BR-O-11: an invoice with an O breakdown group shall contain no other breakdown group — and BR-O-12..14 extend that to lines, allowances and charges. O is all-or-nothing: you cannot put one out-of-scope line on an otherwise standard-rated invoice. Split it into two documents.
  • The exemption reason is still required (BR-O-10, code VATEX-EU-O).

Z, E and G: three zeros that aren't interchangeable

The remaining zero-rate categories are milder but still distinct. Z (zero rated) is a taxed supply whose rate happens to be 0 — the seller identifier rules match S, and BR-Z-10 forbids an exemption reason, because nothing is exempt. E (exempt) requires a reason (BR-E-10), but is the flexible one: any applicable VATEX code or plain text in BT-120 will satisfy it, since national exemption grounds vary. G (export outside the EU) works like E with a fixed meaning — BR-G-10 wants a reason meaning "Export outside the EU", VATEX code VATEX-EU-G. The classic mix-up is using Z for exports or intra-community sales because "it's 0% anyway": the arithmetic passes, the semantics are wrong, and receiver-side systems (and increasingly, tax administrations doing e-reporting) care about the semantics.

Catching category bugs before the receiver does

Everything above is a document-layer concern. Your Peppol access point will happily transport an AE invoice with no exemption reason or an O invoice carrying your VAT number — transport doesn't re-check business rules — and the rejection arrives days later from the receiver's system, stripped of context. Validating at build time turns the same failure into a machine-readable finding in your CI logs:

curl -s -X POST https://fakturwire.com/v1/validate \
  -H "Authorization: Bearer $FAKTURWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profile": "peppol-bis-3",
    "xml": "<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\">…</Invoice>"
  }'

For a reverse-charge invoice missing its exemption reason:

{
  "valid": false,
  "findings": [
    {
      "rule": "BR-AE-10",
      "severity": "error",
      "message": "A VAT breakdown (BG-23) with VAT Category code (BT-118) \"Reverse charge\" shall have a VAT exemption reason code (BT-121), meaning \"Reverse charge\" or the VAT exemption reason text (BT-120) \"Reverse charge\" (or the equivalent standard text in another language).",
      "path": "/Invoice/cac:TaxTotal/cac:TaxSubtotal[1]/cac:TaxCategory"
    }
  ],
  "counts": { "error": 1, "warning": 0 }
}

That's an HTTP 422 — and a 422 is never billed, so failed validations in CI cost nothing.

The checklist version:

  • One breakdown group per category (per rate for S); taxable amounts are per-category sums.
  • AE and K: rate 0 written explicitly, tax 0, exemption reason code (VATEX-EU-AE / VATEX-EU-IC).
  • AE needs both parties fiscally identified; K needs the buyer's actual VAT number — plus delivery date/period and deliver-to country.
  • O: no rate element, no VAT identifiers, no other categories on the document.
  • Z never has an exemption reason; E and G always do.
  • Which letter applies is tax advice; whether the document is consistent with the letter is automatable — automate it.

Try it now: paste an invoice into the free validator — no account needed — or sign up for 50 free credits and put /v1/validate in your pipeline so a wrong category letter surfaces in seconds, not in a receiver's rejection queue.


Last verified: 2026-08-05. Sources: Peppol BIS Billing 3.0 — UNCL5305 VAT category code list (category codes and definitions, incl. the Italian B A-deviation); Peppol BIS Billing 3.0 — VATEX exemption reason code list (VATEX-EU-AE/IC/G/O and their BT-121/category bindings); BR-AE-02 rule page (identifier requirements); EN 16931 rule texts — BR-AE/BR-IC/BR-O/BR-S/BR-E/BR-G families; Peppol BIS 3.0 VAT category guide.