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
AEline's VAT rate (BT-152) shall be 0 (zero) — omittingcbc:Percentis a different failure than writing0. - 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
AEbreakdown group needs an exemption reason code (BT-121) meaning "Reverse charge" — in the VATEX list that's the codeVATEX-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
Kbreakdown 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
Oline 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
Oinvoice it produces is invalid. - No mixing. BR-O-11: an invoice with an
Obreakdown group shall contain no other breakdown group — and BR-O-12..14 extend that to lines, allowances and charges.Ois 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. AEandK: rate0written explicitly, tax0, exemption reason code (VATEX-EU-AE/VATEX-EU-IC).AEneeds both parties fiscally identified;Kneeds 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.Znever has an exemption reason;EandGalways 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.