When building a Phase Two–compliant e-invoicing solution, producing an XML file is not enough. That file must conform to theInvoice Schema published by the Zakat, Tax and Customs Authority (ZATCA). The schema is the technical contract that defines the correct shape of an invoice: which elements are allowed, where they sit, and what kind of value belongs inside each element. Any deviation from this contract makes the invoice rejected before the business rules are even reached.
This technical guide is aimed at developers and integration engineers. It focuses precisely on one aspect: what an XSD schema is, how an invoice is validated against it, and the difference between schema validation and business-rule validation. We will not explain how to build XML from scratch here, nor the UBL 2.1 standard, nor the full ordering of invoice elements. Each of these topics has its own dedicated article in this track, and we will point to them where relevant so you can move to them when needed.
Qoyod handles this entire layer automatically: it generates a UBL 2.1–compliant XML file, signs it, and sends it to the Fatoora platform. But understanding the schema itself helps you read error messages, design your integrations, and diagnose any rejection before it becomes an operational problem.
What is the Invoice Schema?
The invoice schema is an XSD file (short for XML Schema Definition). It is a formal document that describes the allowed structure of an XML file. Think of it as a strict “blank template”: it defines the elements, the attributes, their sequence, how many times they may repeat, and the data types inside them.
The Zakat, Tax and Customs Authority builds its schema on the UBL 2.1standard, an open international standard for business documents. The Authority does not invent a new structure from scratch. Instead, it takes the standard UBL schemas (such as UBL-Invoice-2.1.xsd and its sub-schemas in the common-component namespaces), then layers its own national constraints for the Saudi invoice on top of them. The UBL 2.1 standard itself and its full role have a separate article in this track.
The core idea: the schema answers one question only: “Is this file structurally well-formed?”. The schema does not care whether the tax amount is calculated correctly, nor whether the tax number is real. Those are business-rule questions, and we will detail them later.
The core components of the schema
An XSD schema describes three things about every part of the invoice:
- Elements: the allowed nodes such as
cbc:IDandcbc:IssueDateandcac:AccountingSupplierParty. - Data types: is the value text, a date, a decimal number, or a value from a predefined list.
- Cardinality: how many times an element may or must appear. For example: the invoice number is mandatory and appears once, while invoice line items repeat at least once.
Together, these three components form the “structural contract” that every invoice must comply with before the Authority looks at it at all.
The sequence rule and why order matters
What surprises developers coming from the JSON world most is that XML is order-sensitive. In JSON you can order the keys however you like. In XML built on an XSD schema that uses the xsd:sequenceelement, order is part of the contract. If the schema requires cbc:ID then cbc:UUID then cbc:IssueDate to appear in that succession, then swapping them breaks validation even if all the elements are present and their values are correct.
The reason is that the UBL schema defines most compound nodes inside a xsd:sequenceblock, which literally means “these elements in this order.” There is an alternative called xsd:choice that allows choosing one element from a set, but it is rare in the invoice definition. So the practical rule for the developer: follow the order the schema imposes literally, and do not rely on “the element is present” alone.
Restrictions inside the type
An XSD schema does not stop at specifying “text” or “number.” It can impose finer constraints on the value through elements such as xsd:pattern andxsd:enumeration andxsd:maxLength. For example, the invoice type code may be restricted to a closed list of allowed values via enumeration, so the validator will not accept any code outside it. And a text field’s length may be capped via maxLength. These constraints are still “structural” in the sense that they are checked mechanically, but they approach the boundary of business rules without crossing it. The difference is that the schema does not compare two values against each other, nor perform a calculation; it checks each value individually against a fixed constraint.
What does an XSD schema actually look like?
Let’s take a simplified example. The definition of the invoice number in an XSD schema specifies that it is a mandatory text element appearing exactly once. The syntax looks like this:
What does this definition enforce? Three clear conditions:
minOccurs="1"means the element is mandatory. An invoice without anIDis rejected by the validator immediately.maxOccurs="1"means it appears only once. Two elements with the same name break the schema.- The type
normalizedStringmeans the value is text. The schema does not require it to be a “real invoice number,” only a valid string.
And let’s see how these elements look inside an actual XML invoice that complies with the schema:
Notice the namespaces at the top of the document. These are not a cosmetic detail. The validator uses them to know which schema to apply to each element. The cbc:ID element is validated against the CommonBasicComponentsdefinition, while cac:AccountingSupplierParty is validated against CommonAggregateComponents. The full order of these elements and the structure of the document as a whole have a dedicated article (E-Invoice Structure) in this track.
Why are there multiple XSD files?
You might expect a single XSD file describing the entire invoice. In reality, the UBL schema is split into several files linked through xsd:importinstructions. The main file, UBL-Invoice-2.1.xsd , imports the common basic-components file, CommonBasicComponents, the common aggregate-components file, CommonAggregateComponents, and the unqualified data-types files. During validation, the tool loads the main file and follows the imports automatically.
The practical impact on the developer: all imported schema files must be available locally in their correct paths at validation time. A single missing imported file fails the whole operation with a message about a “schema that cannot be loaded”—a message that confuses anyone who thinks the problem is in their invoice when the problem is in the validation environment itself. That is why it is preferable to assemble the full official schema package from the Authority’s documentation, not a single standalone file.
How does schema validation work?
Schema validation is a purely mechanical process. The validator takes two files: an XML invoice on one side, and an XSD file on the other. It then compares the first against the second, element by element. The result is binary: either “structurally valid” or “invalid,” with a list of the deviation locations.
What does the schema validator check?
The tool checks four aspects only, all of them structural:
- Presence of mandatory elements: is every element marked
minOccurs="1"actually present? - Correct order: do the elements appear in the sequence the schema imposes? XML is order-sensitive within sequenced nodes.
- Data types: is the date value actually a date? Is the decimal value a number?
- Closed values (code lists): is a value such as the currency code from the allowed list?
Any failure in one of these four produces a schema validation error. And importantly: this check performs no calculation, connects to no database, and does not verify the “truth” of the information in reality. It is a purely formal check.
Invoice XML file
XSD schema validation
Valid: proceeds to business rules
A practical example of validating programmatically
If you want to run schema validation yourself in a development environment, the process is straightforward in most languages. Using Java and the standard validation library, it looks like this:
The same logic is available in Python via the lxml:
In both cases, the result is either silent success or a precise list of errors pointing to the offending line and element. This precision is what makes schema validation an excellent diagnostic tool during development.
Common schema validation errors
When building the integration, you will meet a limited set of recurring schema errors. Knowing them in advance saves hours of diagnosis. Here are the most common:
1. Missing mandatory element
The most common error. The developer forgets to include an element marked minOccurs="1". For example, an invoice without an cbc:IssueDate. The error message is of the type:
2. Elements in the wrong order
The UBL schema imposes a specific sequence. Placing cbc:IssueDate after cbc:InvoiceTypeCode instead of before it breaks the schema, even if both elements are present. The usual message:
3. Invalid data type
Putting text inside an element that expects a number, or a date in the wrong format. For example, 2026/06/23 instead of 2026-06-23. The schema enforces the ISO 8601 format for dates, and any deviation from it is an error.
4. Value outside the closed list
Some fields accept values from a defined list only. Putting a currency code that does not exist in the approved currency list, or an invalid invoice type code, produces a validation error. These errors are harder to spot because the element “looks” correct in form.
5. Namespace problem
A subtle but common error. If you declare a namespace incorrectly in the document root, or forget to declare one, the tool fails to link the elements to their definitions. The result is a message saying the element is “not defined” even though it is written with the correct name. The reason is that the name alone is not enough; it must be paired with the correct namespace to match the schema.
The common thread among all these errors: none of them has anything to do with the truth of the information in reality. An invoice may pass schema validation perfectly while carrying a fake tax number or an incorrectly calculated tax amount. This is exactly where the second layer comes in.
How do you read a schema error message?
Schema error messages follow a consistent pattern that helps with fast diagnosis. They usually begin with a code such as cvc-complex-type or cvc-datatype-valid, and this code tells you the type of violation directly. After it comes the name of the offending element, then a description of what was expected. Read the message in three parts: what the code is, which element, and what was expected. This trio is usually enough to pinpoint the line and fix it without guessing.
The difference between schema validation and business-rule validation
This is the most important point in the entire guide. The Zakat, Tax and Customs Authority validates the invoice across two completely separate layers, each with different logic and a different type of error.
| Criterion | Schema validation (XSD) | Business Rules |
|---|---|---|
| Scope | Document structure only | Logic and data correctness |
| Reference | XSD schema | BR-KSA codes |
| Example error | Missing element or wrong order | Mismatched total or invalid tax number |
Schema validation: is the structure correct?
As we saw, this layer is mechanical and structural. Its reference is the XSD file. Its only question: “Is the file built soundly?” This layer knows nothing about Saudi Arabia, nor about VAT, nor about accounting logic. It is as generic as the UBL standard itself.
Business-rule validation: is the content logical and correct?
This layer applies the business rules specific to the Saudi invoice. These rules are usually defined by codes such as BR-KSA-XX for the national rules andBR-XX for rules derived from the European standard. Examples of what it checks:
- Does the sum of the line-item amounts equal the invoice total? (an arithmetic rule)
- Does the VAT amount equal the taxable base multiplied by 15%?
- Does the seller’s tax number follow the correct format (15 digits starting and ending with the digit 3)?
- Is the issue date not in the future?
- Is the exemption reason code present when the tax is zero?
The practical difference: an invoice may be schema-valid yet fail the business rules. Imagine an XML file built structurally perfectly, but the sum of its line items is SAR 1,000 while the written total is SAR 1,200. The schema does not calculate, so it passes the invoice. The business-rule layer, however, rejects it because the arithmetic logic is broken.
Temporal order matters too: schema validation comes first. If the invoice fails structurally, there is no point in checking its logic at all. That is why validation systems always start with the structural layer, then move to the logical one. The details of the business rules and their full codes are a separate topic, with its own dedicated article (Validation Rules) in this track.
Why did the Authority separate the two layers?
Separating the two layers is a deliberate design decision with a practical reason. Structural validation is computationally cheap and fast, and can be run by any standard XSD engine without any knowledge of the Saudi tax context. Business-rule validation, on the other hand, is more expensive, because it requires calculations and changing national rules. Logically, the cheaper layer filters out structurally broken invoices first, so the more expensive layer does not spend its resources on files that would never succeed anyway.
This separation benefits the developer too. When an error appears, you know immediately which layer rejected the invoice from the shape of the message. A cvc- structural error concerns the schema, and a BR- logical error concerns the business rules. This distinction points the diagnosis in the right direction from the very first moment, and prevents wasting time looking for an arithmetic error when the problem is a missing element, or vice versa.
Where does identifier-format validation inside Qoyod fit?
You might wonder where Qoyod’s identifier-format validation feature fits within these two layers. The answer: it is a third layer prior to both, and it runs on the client side before sending at all. Qoyod ensures that the tax number, commercial registration, and others follow the correct format (digit count and prefix) at the moment of entry. This is a light preliminary check that catches one of the most common causes of warnings early, but it does not replace the Authority’s full two-layer validation. The Authority remains the entity that validates the invoice definitively.
Schema-compliant invoices without writing a single line of XSD
Qoyod takes care of generating the UBL 2.1–compliant XML file, signing it, and sending it to the Fatoora platform. You issue the invoice, and we handle the schema.
Start your free trial and issue invoices compliant with the Authority
The role of the schema in the invoice’s journey through the Fatoora platform
Let’s place schema validation in its operational context. When you send an invoice to the Fatoora platform, it passes through a series of stations. Schema validation is almost the first gate.
- Generation: your accounting system builds the XML file in UBL 2.1 format.
- Signing: the file is signed digitally using the cryptographic stamp identifier (CSID) issued by the Authority.
- Schema validation: the platform first ensures the file is structurally compliant with the XSD.
- Business-rule validation: it then applies the BR rules to the content.
- Clearance or reporting: real-time clearance for tax invoices (B2B), or reporting within 24 hours for simplified invoices (B2C).
If the invoice fails at the third station, the journey stops. It reaches neither the business rules nor clearance. That is why developers say schema errors are the “cheapest” errors: they are caught early, their messages are precise, and their fix is usually clear.
Generate the invoice in XML format
Sign with the CSID certificate
XSD schema validation (the first gate)
Business-rule validation
Clearance or reporting via the Fatoora platform
How Qoyod handles the schema layer on your behalf
The point of understanding the schema is not to write it by hand. The point is to understand what happens under the hood. Qoyod handles the schema layer entirely:
- It generates a UBL 2.1–compliant XML file with all mandatory elements in their correct order.
- It signs the invoice digitally using the CSID and manages its lifecycle for each branch or device.
- It produces a PDF/A-3 file with the XML embedded inside it, per the presentation requirement in Phase Two.
- It validates the format of identifiers (such as the tax number and commercial registration) at entry, before sending, to reduce one of the most common causes of warnings.
An important point for accuracy: identifier-format validation inside Qoyod is a light preliminary check on the client side, and is not a substitute for the Authority’s full validation. The Authority is the entity that validates the invoice definitively across the schema and business-rule layers. Qoyod sends what you issue, and helps you issue it correctly the first time.
This division spares you from building your own XML generator, from tracking the XSD schema updates the Authority releases, and from managing digital certificates manually. These are tasks that usually consume development teams’ time without adding value to your core business.
Schema updates are a point many people overlook. From time to time, the Authority publishes updated versions of the technical specifications and the schema package, which may add elements, change constraints, or update closed-value lists. Any team building its own generator bears the burden of tracking these updates and applying them before their effective date, otherwise its invoices suddenly start getting rejected. When using a compliant solution, this responsibility shifts to the solution provider, so your invoices stay conformant without any intervention from you.
Where do you go after this guide?
We covered here the schema layer alone: what XSD is, how it is validated, and the difference between it and the business rules. To complete the technical picture in the e-invoicing technical documentation track, follow the neighboring topics:
- XML invoice and technical format: to understand what XML is in the first place and how it represents the invoice, see the “XML Invoice” article in this track.
- The UBL 2.1 standard: to understand the international standard on which the Authority’s schema is built, see the “UBL 2.1 Standard” article.
- E-invoice structure: to understand the full ordering of document elements and the main nodes, see the “Invoice Structure” article.
- Validation rules (Business Rules): for the second layer and its full codes (BR-KSA), see the “Validation Rules” article in this track.
Together, these articles form an integrated technical reference for every developer building or integrating a solution compliant with Phase Two of e-invoicing in Saudi Arabia.
Frequently asked questions
What is the difference between the invoice schema (XSD) and the XML file?
The XML file is the actual invoice with its data. The XSD schema is the template that describes the correct shape of any XML invoice. The first is a data document, the second is a rules document. The tool validates the first against the second.
Does passing schema validation mean the invoice is accepted by the Authority?
No. Passing the schema means only that the structural form is correct. The invoice still needs to pass the business-rule layer, which checks the arithmetic logic and the correctness of the information. The two layers are separate conditions, and both are mandatory.
Where do I get the official XSD schema files?
The Zakat, Tax and Customs Authority publishes the schema package and technical specifications within the Phase Two documentation on its official website. These schemas are built on the UBL 2.1 standard with national additions specific to Saudi Arabia.
What are the most common schema validation errors?
A missing mandatory element, then elements in the wrong order within sequenced nodes, then an invalid data type such as a wrong date format. Together, the three represent most cases of structural rejection.
Do you need to write an XSD schema yourself to comply with Phase Two?
No. A compliant e-invoicing solution such as Qoyod generates schema-conformant XML automatically, and tracks the schema updates issued by the Authority. You issue the invoice, and the technical layer is managed for you.
Does schema validation verify the correctness of amounts and calculations?
No. Schema validation is purely structural. It performs no calculation. Checking the correctness of amounts happens in the business-rule layer, which is a separate layer that comes after passing the schema.