Where ZATCA's validation rules differ from their own text

By · Tested on SDK 3.4.8

ZATCA ships its e-invoicing business rules inside the SDK as compiled XSLT. Each rule reports a message and a test, but the condition that actually runs is a separate line of code, and sometimes it checks something different. We ran the official rule files from SDK 3.4.8 against ZATCA's own sample invoices, changing one thing at a time. These are the six differences that matter in practice.

  1. Out-of-scope lines (category O): use VATEX-SA-OOS, not VAT-OOS-SA
  2. BR-KSA-27 (QR code) is only enforced on simplified invoices
  3. The previous-invoice-hash rules accept any value
  4. BR-KSA-10 (buyer address) applies to Saudi buyers too
  5. BR-KSA-16 accepts far more payment codes than its text suggests
  6. ZATCA's own simplified sample fails BR-KSA-98 today

Out-of-scope lines (category O): use VATEX-SA-OOS, not VAT-OOS-SA

Many integrations, including ours until this test, use VAT-OOS-SA as the reason code for category O. Under SDK 3.4.8 that code raises BR-KSA-CL-04, while VATEX-SA-OOS validates clean.

Test: We generated the same out-of-scope invoice twice, once with each code, and ran both rule files on it.

BR-KSA-27 (QR code) is only enforced on simplified invoices

The message says the document must contain a QR code. The check that runs only applies to simplified invoices: removing the QR from ZATCA's own standard sample invoice raises nothing, while removing it from the simplified sample raises BR-KSA-27.

Test: ZATCA's standard and simplified sample invoices from SDK 3.4.8, each with the QR block removed.

The previous-invoice-hash rules accept any value

BR-KSA-26 describes exactly how the previous invoice hash (PIH) must be computed, but the rule check only needs the PIH to be present and non-empty. A made-up base64 string passes both BR-KSA-26 and BR-KSA-61. Keep your hash chain correct anyway: the rules file is not where it gets verified.

Test: ZATCA's standard sample with the PIH replaced by an arbitrary base64 string.

BR-KSA-10 (buyer address) applies to Saudi buyers too

The message talks about buyers whose country is not SA. The executed check applies to every standard invoice: a Saudi buyer without a street name raises BR-KSA-10 (and BR-KSA-63).

Test: ZATCA's standard sample with the buyer's StreetName removed, buyer country SA.

BR-KSA-16 accepts far more payment codes than its text suggests

The rule's own test lists only a few codes (10, 30, 42, 48, 1). The executed check accepts the wider UNTDID 4461 list: code 68 passes, code 999 fails. Note also that BR-KSA-16 is the payment means rule; the invoice counter (ICV) rules are BR-KSA-33 and BR-KSA-34.

Test: ZATCA's standard sample with PaymentMeansCode set to 68, then 999.

ZATCA's own simplified sample fails BR-KSA-98 today

BR-KSA-98 (submit simplified invoices within 24 hours) compares the issue date with the current time, so any old invoice, including the official sample dated 2022, raises it. Expect this warning on test fixtures with fixed dates.

Test: ZATCA's simplified sample invoice validated unchanged.

Method

Rules: the two Schematron files in ZATCA E-invoicing SDK 3.4.8 (KSA rules and EN 16931), compiled with Saxon and run unchanged. Inputs: ZATCA's own sample invoices from the same SDK, edited one field at a time. You can reproduce every case with the free validator, which runs the same files in your browser, and every rule's executed condition is in the open dataset.