BR-KSA-83 Warning — the invoice is accepted

Exemption reason code without its reason text (BT-120)

A VAT breakdown that carries an exemption reason code carries its text as well. The test as the Authority's SDK runs it checks that the text is there, not how it is worded: a code with no text, an empty text or only spaces fails here. It is a warning, so the invoice is accepted.

The message text as the Authority sends it in English, unedited

A VAT breakdown (BG-23) with VAT Category code (BT-118) 'Exempt from VAT' or 'Zero rated' or 'Not subject to VAT' shall have a VAT exemption (or exception) reason text (BT-120) with one of the values from paragraph 11.2.4 of XML implementation standards on Tax exemption (or exception) reason text - specific to Saudi Arabia.

What does this mean?

The exemption reason in the VAT breakdown is two fields side by side: the code (BT-121) in cbc:TaxExemptionReasonCode, for machines, and the text (BT-120) in cbc:TaxExemptionReason, for whoever reads the document. Both sit inside cac:TaxSubtotal/cac:TaxCategory for category Z, E or O. This rule asks for the text whenever the code is there.

The executable test in the Authority's SDK (R3.4.8) is narrower than its message: if the code element exists, the text element must exist and something must be left in it once spaces are removed. That is all it checks. The "one of the values from paragraph 11.2.4" the message mentions did have a stricter test, comparing the text with the Authority's table; it is in the same file, disabled inside a comment. Write the table's wording anyway: the message asks for it, the disabled test may come back, and we cannot see what the Authority's live server runs.

When it stays silent: a breakdown with no code at all does not reach it — absence has its own codes, BR-KSA-69, BR-KSA-23 and BR-KSA-24. A text without a code does not trigger it either, because the test starts from the code. And a standard-rated S breakdown is outside it altogether.

It is a warning: the invoice is accepted and recorded, with the warning attached. Category O has a place of its own in the table: it sets no text for it, saying instead that the text is free, written by the taxpayer case by case, while the code stays VATEX-SA-OOS.

Why does it happen?

Ordered from the most common to the least — your cause is most likely the first or the second.

  • A mapping that writes the code alone because the source system stores nothing else, leaving the text for someone to "add later".
  • A template that always writes the text element and fills it from a lookup that missed — because the code was stored in a different spelling from the key — so <cbc:TaxExemptionReason/> goes out empty or full of spaces.
  • The text written somewhere else: in the document note cbc:Note, on the line, or printed on the PDF only, while the rule reads nothing but the category block in the breakdown.
  • A document mixing two categories — zero-rated and exempt — where the text is fetched once for the document and written on the first breakdown only, leaving the second with a code and no text.

How to fix it

3 steps, then send the invoice again.

  1. 1
    Write the code and the text together, from one table

    One function that takes the code and returns the pair, and no path in the code that writes one without the other: <cbc:TaxExemptionReasonCode>VATEX-SA-29</cbc:TaxExemptionReasonCode><cbc:TaxExemptionReason>Financial services mentioned in Article 29 of the VAT Regulations</cbc:TaxExemptionReason>. The two elements follow each other inside cac:TaxCategory, after cbc:Percent and before cac:TaxScheme. The value of the code has its own rule: BR-KSA-CL-04.

  2. 2
    Take the wording from the Authority's table

    The table is paragraph 11.2.4 of the XML Implementation Standard on zatca.gov.sa, with a column for English and one for Arabic. Its English wording in version 1.2 includes: VATEX-SA-32, Export of goods; VATEX-SA-33, Export of services; VATEX-SA-35, Medicines and medical equipment; VATEX-SA-36, Qualifying metals; VATEX-SA-EDU, Private education to citizen; VATEX-SA-HEA, Private healthcare to citizen; and VATEX-SA-30, Real estate transactions mentioned in Article 30 of the VAT Regulations. Copy it as it stands, and do not shorten it.

  3. 3
    Never write an empty element

    If your table has no text for the code, stop the document before signing and fix the table, rather than writing the element empty: a document with an empty reason is signed and reported with the gap in it, while a stopped one is fixed in a minute and goes out clean. How to read the response when several codes arrive together is in ZATCA error codes explained.

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. In ZATCA Tools a code is never written without its text: both come from one table in TaxCategories that ties every code to an English text, the VAT breakdown takes them together in the same step in TaxBreakdown, and no code in the table is without a text — so a code never goes out alone and a text element is never empty. Category O always carries VATEX-SA-OOS and its text. When the reason for Z or E is left out, there is neither code nor text, which brings another warning, BR-KSA-69 or BR-KSA-23, not this one. The texts match table 11.2.4 of the XML implementation standard (version 1.2) word for word.

Related codes

Frequently asked questions

Must the text match the Authority's table word for word? +
The executable test in the Authority's SDK is satisfied by any non-empty text, and the test that compared the text with the table is in the same file but disabled. The message still asks for the table's values, and we cannot see what the live server runs; so copy the table's wording as it stands, and do not build on how lenient the test is today.
Do I write the text in Arabic or in English? +
The table in paragraph 11.2.4 has a column for each language, and the executable test accepts any non-empty text. The Authority's own sample of a simplified invoice with a zero-rated item in its SDK writes both, separated by a vertical bar: Medicines and medical equipment | الأدوية والمعدات الطبية.
What text does an out-of-scope supply need? +
The code VATEX-SA-OOS is fixed, but the table leaves the text free: the taxpayer writes it case by case. Write a short sentence saying why the supply is outside the scope, and do not leave it empty.
I wrote the reason in the invoice note. Is that not enough? +
No. The rule reads one element and one only: cbc:TaxExemptionReason inside the category block of the VAT breakdown. The note, the line and the printed file are all outside what it reads.
How does it relate to BR-KSA-CL-04? +
One block, two tests: BR-KSA-CL-04 checks the value of the code against its category's list, and this one checks that the text is there beside the code. They can arrive together on the same breakdown, and each is fixed in its own place.
You fixed this one — now avoid the next

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

← All ZATCA error codes