If VAT category Code (BT-118) is 'Z', or 'E', VAT exemption (or exception) reason code (BT-121) must exist with one of the values from paragraph 11.2.4 of XML implementation standards on Tax exemption (or exception) reason code - specific to Saudi Arabia.
What does this mean?
The rule runs on the VAT breakdown (BG-23), not on the line: on every cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory whose letter in cbc:ID is Z, E or O. It reads the reason code cbc:TaxExemptionReasonCode there and compares it with the list for the letter beside it, not with all the lists together. The line's cac:ClassifiedTaxCategory carries the letter and the rate, and this rule does not look at it.
The lists, as the executable test in the Authority's SDK (R3.4.8) has them: for zero-rated Z, VATEX-SA-32, VATEX-SA-33, VATEX-SA-34-1 to VATEX-SA-34-5, VATEX-SA-35, VATEX-SA-36, VATEX-SA-EDU, VATEX-SA-HEA and VATEX-SA-MLTRY; for exempt E, VATEX-SA-29, VATEX-SA-29-7 and VATEX-SA-30; and for out of scope O, a single code, VATEX-SA-OOS. The message names Z and E only; the test covers O as well.
The zero-rated list inside the SDK carries four more codes that the table in paragraph 11.2.4 of version 1.2 of the XML Implementation Standard does not: VATEX-SA-DIPLOMAT, VATEX-SA-DUTYFREE, VATEX-SA-ROYALDECREE and VATEX-SA-32(bis). The test accepts them, but check the current table on zatca.gov.sa before you build on them.
The comparison is literal: the code is one exact word from the list, in capitals; spaces around it are trimmed before comparing, while a space inside it fails it. And the rule speaks only when a non-empty code is there: a breakdown with no code, or an empty one, passes it — absence has its own codes: BR-KSA-69 for zero-rated, BR-KSA-23 for exempt and BR-KSA-24 for out of scope. So this code always means one thing: you wrote a code, and it is not on its category's list.
It is a warning: the invoice is accepted and recorded, with the warning attached. But the code is the basis on which this base carries no VAT, and a code off the list is a basis the list does not know. When the code is VATEX-SA-EDU or VATEX-SA-HEA, another rule joins in, and that one is an error: BR-KSA-49 requires the buyer's national ID.
Why does it happen?
Ordered from the most common to the least — your cause is most likely the first or the second.
-
A code without its suffix:
VATEX-SA-34on its own, where the list only knowsVATEX-SA-34-1toVATEX-SA-34-5; or a suffix invented by analogy, such asVATEX-SA-29-1. -
A different spelling:
vatex-sa-35in lower case,VATEX_SA_35with underscores, orVATEX SA 35with spaces. -
A dash that is not a hyphen: a code copied from a PDF or a Word file in which the ordinary hyphen became an en dash
–, so it looks right and matches nothing. -
A code from another category's list:
VATEX-SA-29(exempt financial services) on a zero-rated breakdown,VATEX-SA-32on an exempt one, or anything other thanVATEX-SA-OOSon an out-of-scope one — usually from a mapping that takes the reason from one list for everything that is not standard-rated. -
The reason text in the code field:
Export of goodswhereVATEX-SA-32is expected. -
European codes from an imported system, such as
VATEX-EU-GorVATEX-EU-O; the Saudi list does not know them.
How to fix it
3 steps, then send the invoice again.
-
1
Make the code a value from a closed list, not free text
Store the code in your system as a value from a fixed enumeration tied to its category, not a text field that takes whatever a user types. If the code comes in from outside, normalise it once — capitals, no surrounding spaces — then refuse anything that does not match its category's list before the XML is built, rather than sending it and waiting for the warning. The official table is paragraph 11.2.4 of the XML Implementation Standard on zatca.gov.sa.
-
2
Write it in the VAT breakdown, under the letter it belongs to
Its place is the category block inside the breakdown, after the letter and the rate, with the reason text beside it:
<cac:TaxCategory><cbc:ID>Z</cbc:ID><cbc:Percent>0</cbc:Percent><cbc:TaxExemptionReasonCode>VATEX-SA-35</cbc:TaxExemptionReasonCode><cbc:TaxExemptionReason>Medicines and medical equipment</cbc:TaxExemptionReason><cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme></cac:TaxCategory>. Make sure the code is from the list of the letter above it: a correct code under the wrong letter fails just as an invented one does. The text has its own rule: BR-KSA-83. -
3
Pick the suffix that describes the supply
The international transport codes are five, not one:
VATEX-SA-34-1transport of goods,VATEX-SA-34-2transport of passengers,VATEX-SA-34-3services directly connected and incidental to international passenger transport,VATEX-SA-34-4supply of a qualifying means of transport, andVATEX-SA-34-5services relating to goods or passenger transportation. Which one fits your supply is a tax question for zatca.gov.sa; what the rule says is that the code without a suffix is none of them.
This code does not block acceptance, so the invoice you have is compliant. Correct the data so the warnings disappear from future invoices.
Does ZATCA Tools prevent it?
Yes. The reason code in ZATCA Tools is never free text: it is picked from a fixed list of fifteen codes in TaxCategories, each tied to its category, and reasonCodeFor drops any code that does not belong to the line's category before the VAT breakdown is built — so a code that reaches the XML is always from its category's list. The invoice form only offers the reasons of the chosen treatment; the API upper-cases what it receives and then refuses the request with a 422 if the code is not on the list or belongs to another category; and category O always takes VATEX-SA-OOS. Two limits, stated plainly: our list does not yet include VATEX-SA-MLTRY or the four newer codes, so a merchant who needs one of them cannot pick it here today; and the reason is optional for Z and E, so when it is left out no code is written at all — which brings another warning, BR-KSA-69 or BR-KSA-23, not this one.
Related codes
BR-KSA-83
Warning
BR-KSA-69
Warning
BR-KSA-23
Warning
BR-KSA-24
Warning
BR-KSA-18
Rejects the invoice
BR-KSA-49
Rejects the invoice
Frequently asked questions
I wrote the code correctly and the warning is still there. Where is the mistake? +
cbc:TaxExemptionReasonCode in every cac:TaxSubtotal, character by character.How does it differ from BR-KSA-69, 23 and 24? +
Does the code go on every line as well? +
cac:ClassifiedTaxCategory, and the reason is written once, on the VAT breakdown for its category — which is how the Authority's own sample of a simplified invoice with a zero-rated item in its SDK writes it. This rule reads the breakdown and nothing else.The invoice was accepted with this warning. Do I need to do anything about it? +
Should I use VATEX-SA-DIPLOMAT or VATEX-SA-DUTYFREE? +
Z, but neither is in the table of version 1.2 of the XML Implementation Standard. Check the current table on zatca.gov.sa, and whether the basis applies to your supply, before you write either.ZATCA Tools builds the signature, the PIH, the counter and the encoding for you, and validates your data before it is sent. Start free, with no credit card.
Start for free