BR-KSA-27Simplified invoice carries no QR code reference

Mutabiq checks Saudi ZATCA Phase 2 e-invoice XML before you submit it: pre-validation against published ZATCA requirements, not an approval by the authority. This page explains one rule, BR-KSA-27.

Validate 5 invoices free

Five checks a month on the Free plan. The file is checked in memory and is never stored.

The message ZATCA prints

[BR-KSA-27]-The document must contain a QR code (KSA-14), and this code must be base64Binary.

Also cited in this report

  • BR-CL-KSA-14

    [KSA-14]Field character limit for QR Code field has been exceeded. The maximum character limit for this field is 1000 characters.

What Mutabiq reports

One entry for each way this rule can be reported.

Reported as
What kind of value was found — empty, not_15_digits and the like — never the value itself.

Simplified invoice carries no QR code reference

Reported asreference_missingthe reference is missing

What is wrong

The document carries no cac:AdditionalDocumentReference whose cbc:ID is QR, so it has no QR code on it at all. SDK 3.4.8 flags a simplified invoice in that state under BR-KSA-27, which requires the document to carry a QR code (KSA-14), as a warning, not a rejection: the finding is reported without failing the document by itself. The id is compared after whitespace is normalised, so spacing around QR is not what is wrong; but it is compared exactly otherwise, so a reference labelled qr in lower case, or QRCODE, is not the reference this rule looks for and reads as absent. The rule applies to simplified invoices only - a standard invoice with no QR code is not reported by it.

What to check in your ERP

The QR code travels in a document reference block of its own: a cac:AdditionalDocumentReference whose cbc:ID is the literal text QR, holding cac:Attachment/cbc:EmbeddedDocumentBinaryObject with the base64 payload inside it. The usual causes are an export template written for standard invoices and reused for simplified ones without the QR block ever being added, a QR generator that runs for the printed copy and not for the XML, and a mapping that writes the block only when the generator returns a value and skips it silently when it returns nothing. Look at the neighbouring blocks while you are there: the same element carries the invoice counter (ICV) and the previous invoice hash (PIH) under different ids, so a document that carries those and not QR usually means only the QR branch of the mapping is missing.

QR code reference carries no payload element

Reported aspayload_element_missingthe payload element is missing

What is wrong

The document has a cac:AdditionalDocumentReference whose cbc:ID is QR, but there is no cac:Attachment/cbc:EmbeddedDocumentBinaryObject inside it: the reference block is present and the element that would hold the QR code is not. ZATCA flags a simplified invoice in that state under BR-KSA-27, as a warning, which does not by itself reject the document. If the document carries more than one QR reference, any one of them carrying the payload element satisfies the check, so this is reported only when none of them does.

What to check in your ERP

Check the shape of the block your export writes: two levels inside the reference, a cac:Attachment and a cbc:EmbeddedDocumentBinaryObject inside that, with the base64 payload as the second one's text content. The usual causes are a template that writes the reference and its cbc:ID from one loop and the attachment from another that did not run, a QR value written into the reference's own text or into a description element instead of into the attachment, and a nesting level dropped so that the binary object sits directly under the reference. A payload element that is present but empty is a different defect and is reported as its own finding.

No document reference on this invoice carries a non-empty payload

Reported asall_payloads_emptyevery document reference's payload is empty

What is wrong

This is not the finding for an empty QR code, and only rule packs before 2.0.0 report it. In SDK 3.0.8 the part of BR-KSA-27 behind it was not restricted to the QR reference: ZATCA evaluated it over every cac:AdditionalDocumentReference in the document, as an XPath general comparison, so it was satisfied as soon as any one of those references carried a payload that is not the empty string, and it failed only when no additional document reference anywhere in the document carried a non-empty cac:Attachment/cbc:EmbeddedDocumentBinaryObject. A non-empty previous invoice hash (PIH) payload satisfied it on its own even when the QR payload next to it was empty. In SDK 3.4.8, which rule pack 2.0.0 reads, the same conditions read the QR reference's own payload (KSA:366-371), so an empty QR payload is reported as the QR code element being empty, as a warning, and a report produced under 2.0.0 never carries this note.

What to check in your ERP

Because the test spans the whole document, reaching it usually means the attachments are being written as empty elements throughout rather than that one generator failed. Check that the step which fills cac:Attachment/cbc:EmbeddedDocumentBinaryObject runs before the document is serialised, and that it runs for every reference block the document carries - the QR code, and on a simplified invoice the previous invoice hash. A mapping that emits the block structure unconditionally and fills it from a value that is null or an empty string produces exactly this. Fix the generator or the mapping in your e-invoicing module rather than deleting the empty blocks: deleting the QR block moves the document onto the finding for a missing QR reference instead.

QR code payload is not declared text/plain

Reported asno_text_plain_payloadno payload declared text/plain

What is wrong

ZATCA requires the QR code to be declared as text/plain, which is carried in the mimeCode attribute on cac:Attachment/cbc:EmbeddedDocumentBinaryObject inside the QR reference. In SDK 3.4.8, which rule pack 2.0.0 reads, this condition reads the payload of the QR reference itself (KSA:366-371); earlier releases looked at every document reference and were satisfied by any attachment declared text/plain, the previous invoice hash one included. The value is compared after whitespace is normalised and exactly otherwise: text/plain is what is required, and application/octet-stream, base64Binary, an empty attribute and no mimeCode attribute at all each fail. ZATCA flags the simplified invoice under BR-KSA-27 as a warning, which does not by itself reject the document.

What to check in your ERP

The attribute belongs on the element that holds the payload, not on the cac:Attachment above it: mimeCode with the value text/plain on cbc:EmbeddedDocumentBinaryObject. Do not reason the value out from what the payload contains. The payload is base64 of a byte sequence, so application/octet-stream looks the more accurate of the two and draws this note; text/plain is what the checker requires. The usual causes are a serialiser that writes the attachment through a generic binary-attachment helper carrying its own default type, an attribute read from a document-management table, and a template that omits it. Compare against a ZATCA sample simplified invoice, which carries a mimeCode of text/plain on this element.

Simplified invoice's QR code element is empty

Reported aspayload_emptythe payload is empty

What is wrong

On a simplified invoice the QR reference (the cac:AdditionalDocumentReference whose ID is QR) is present, but its cbc:EmbeddedDocumentBinaryObject holds nothing, or only spaces. BR-KSA-27 requires a QR code on a simplified invoice. ZATCA flags this as a warning, which does not by itself reject the document. BR-CL-KSA-14 reports an element with no characters at all as an error.

What to check in your ERP

Generate the QR before the XML is written and write the base64 payload into the element. An empty element usually means the export runs before the QR step, or that the step failed and the export carried on.

The clause that runs

Quoted from the validation-rule stylesheet ZATCA publishes, at the file and line named below. The executed guard is what the check runs; the reported test is what it prints when it fails, and the two are not always the same.

Executed guard

not((cac:AdditionalDocumentReference[normalize-space(cbc:ID) = 'QR'] and exists(cac:AdditionalDocumentReference[normalize-space(cbc:ID) = 'QR']/cac:Attachment/cbc:EmbeddedDocumentBinaryObject) and (normalize-space(cac:AdditionalDocumentReference[cbc:ID = 'QR']/cac:Attachment/cbc:EmbeddedDocumentBinaryObject) != '') and (cac:AdditionalDocumentReference[cbc:ID = 'QR']/cac:Attachment/cbc:EmbeddedDocumentBinaryObject[normalize-space(@mimeCode) = 'text/plain'])) )

Reported test

(cac:AdditionalDocumentReference[normalize-space(cbc:ID) = 'QR'] and exists(cac:AdditionalDocumentReference/cac:Attachment/cbc:EmbeddedDocumentBinaryObject) and (cac:AdditionalDocumentReference/cac:Attachment/cbc:EmbeddedDocumentBinaryObject) != '' and (cac:AdditionalDocumentReference/cac:Attachment/cbc:EmbeddedDocumentBinaryObject[normalize-space(@mimeCode) = 'text/plain']))
Evaluated against
/ubl:Invoice | /cn:CreditNote
Source
vendor/zatca/schematron/20210819_ZATCA_E-invoice_Validation_Rules.xsl:371

As shipped in ZATCA SDK 3.4.8: the copy quoted here is, byte for byte, the file that release ships. The date in the file name is the name ZATCA gives the file; the rules in it are those of SDK 3.4.8.

A worked example

A synthetic document from the measured test corpus that trips this rule, shown where it differs from one that passed. Mutabiq's report names the class of the value, never the value itself.

Document
bad-37-qr-reference-missing.xml
Mutabiq's verdict
Passed
Reported as
reference_missingthe reference is missing

Download this example (.xml)Check it in Mutabiq

This page's example, checked by the same rules your own upload goes through. No upload and no sign-in.

ERP guides

Product names identify the systems only. Mutabiq is independent of their vendors and is not affiliated with or endorsed by any of them.

Rules evaluated against the same part of the document. One wrong value often reports several of them at once.

Check an invoice

Check your own invoice

© 2026 Hayatiq AI Solutions F.Z.E. All rights reserved.