This page gives you a ready-to-use XML invoice for copy and paste: a standard tax invoice (B2B) written entirely to the UBL 2.1 standard adopted by the Zakat, Tax and Customs Authority (ZATCA) in Phase Two of e-invoicing. Every block in the sample is explained in English, line by line, so you understand what it does before you rely on it in the Sandbox or in production.
The difference between this page and the other pages in the developer center matters. Here you find a complete example you copy and try, not an explanation of the format. If you want to understand the technical format of the file, go back to XML Invoice: The Technical Format of the E-Invoice. And if you want to understand the document structure, its three sections, and how they nest into a single tree, go back to E-Invoice Structure. Those two pages explain the form; this page gives you the ready content.
The target audience here is the developer or integration analyst building an invoicing system, connecting an existing system to the Fatoora platform, or testing the API response before launch. The sample below works as a starting point where you replace the seller, buyer, and line-item data with your own establishment’s real data, then run it through the validation stage before sending.
What you will find in this sample
The full sample represents a standard tax invoice issued from one establishment to another. This type is subject toClearance: you send it to the Fatoora platform, the Authority approves and stamps it, then it returns to you to hand over to the buyer. This differs from the simplified tax invoice addressed to individuals, which is issued immediately and reported within 24 hours. We will show the standard sample in full, then explain the differences that turn it into a simplified sample.
The sample covers all the elements Phase Two requires: a header carrying the invoice identity and its parties, at least one line item with the item details and its tax, and a totals block carrying the net value, the tax amount, and the total including tax. It also carries the mandatory technical fields: the unique identifier (UUID), the invoice counter (ICV), the previous invoice hash (PIH), the placement of the cryptographic stamp, and the QR code.
An important methodological note before you start: the cryptographic stamp value, the QR code value, and the hash value in the sample are short illustrative placeholders. These values are generated by your system or the Fatoora platform automatically at issuance using a CSID certificate, and are not written by hand. The sample shows their placement in the file, not their final values.
The full sample: a standard tax invoice (B2B)
Copy the following block in full. It is a structurally valid UBL 2.1 file that begins with the namespace declaration, then passes through the header, the parties, the line item, and the totals. After the block, we explain each section separately.
This file represents a single sale: ten units of an advisory service, at a unit price of SAR 100, so the line net is SAR 1,000, the tax at 15% is SAR 150, and the total is SAR 1,150. Notice how these numbers match across every block of the file. This matching is a core condition for passing the validation stage.
Explaining the namespace declaration (Namespaces)
UBLExtensions: extensions and stamp
The header: identifiers, dates, and type
The parties: seller and buyer
Line items and totals: InvoiceLine and Totals
Every invoice file begins with an XML declaration line that specifies the version and encoding, then the root element Invoice. Inside this element, four namespaces are declared. The default namespace defines the document type itself as a UBL 2.1 invoice. The cac namespace abbreviates “Common Aggregate Components” and is used for composite blocks such as parties and line items. The cbc namespace abbreviates “Common Basic Components” and is used for single values such as the date and the amount. And the ext namespace is dedicated to the extensions section that carries the signature and stamp.
Never modify these lines. The encoding must remain UTF-8 because the file contains Arabic text such as the establishment name and the item name. Any error in the namespace URI makes the file invalid against the schema, so it is rejected in the very first step of validation before it reaches any business rule.
To understand why the Authority chose this standard specifically and how it ensures interoperability between different systems, see The UBL 2.1 Standard in E-Invoicing. That page explains the standard; what we do here is apply it in practice.
Explaining the extensions block (UBLExtensions)
The ext:UBLExtensions block comes first inside the root element, before any other field, and this is a mandatory order in the UBL standard. In the sample we deliberately left it nearly empty, because its content is filled automatically at issuance.
When the invoice is issued, your system or the Fatoora platform places inside this block the digital signature built on your establishment’s private key, and thecryptographic stamp linked to the CSID certificate approved by the Authority. Together, these two elements prove that the invoice was issued by a registered establishment and has not been modified after it was stamped.
The most important mistake developers make here is trying to write the signature by hand or copy it from another invoice. The signature is computed on the content of the invoice itself, so every invoice has a unique signature. The sample leaves the section empty only to show you its placement, and the signing process is handled automatically by the CSID certificate. To understand the stamping mechanism in detail, see the cryptographic stamp page in the developer center.
Explaining the invoice header (Header)
| Field | Who generates it |
|---|---|
| ID (invoice number) | Establishment sequence |
| UUID | The system automatically |
| IssueDate/Time | The system |
| InvoiceTypeCode | By invoice type |
| ICV / PIH | The system (counter and chain) |
The header carries the invoice identity. The field cbc:ID is your sequential invoice number, and it must be unique within your books. As for cbc:UUID , it is a globally unique identifier your system generates for each invoice, and it never repeats. Do not confuse the two: the first is your commercial number, and the second is a technical fingerprint. For more detail, see the unique identifier UUID page in the developer center.
The two fields cbc:IssueDate andcbc:IssueTime carry the issue date and time in the standard format. The date is in year-month-day, and the time is in the 24-hour system. These two fields enter into the QR code and signature computation, so any discrepancy between them and the actual send time may trigger a note from the validation rules.
Field cbc:InvoiceTypeCode is the most important in determining the invoice type. The value 388 means a standard tax invoice. And the attribute name whose value is 0100000 is a flag made up of seven positions describing the invoice’s characteristics. The second position here has the value 1, and it means the invoice is issued from an establishment to an establishment, that is, standard and subject to clearance. This flag is what we will change later to turn the sample into a simplified one.
The two fields cbc:DocumentCurrencyCode andcbc:TaxCurrencyCode prove that the currency is the Saudi riyal. In local-market invoices, the two values are SAR always. If the document currency differs from the tax currency, conversion fields must be added, and this is rare in local invoicing.
Explaining the invoice counter (ICV) and the previous hash (PIH)
Below the header come two technical fields that guarantee the sequencing of invoices. The first is the invoice counter ICV: a number that increases by one with each invoice the establishment issues, and never goes backward. In the sample its value is 123, meaning it is invoice number 123 in this device’s chain. For more detail, see the invoice counter ICV page.
The second is the previous invoice hash PIH: an encrypted fingerprint of the invoice that immediately preceded it, encoded in Base64. This value links each invoice to the one before it in an unbreakable chain. If someone deletes an invoice from the middle, the chain breaks and the tampering shows immediately. The first invoice in a device’s life carries a known fixed hash value, then each subsequent invoice takes the hash of its predecessor.
The value shown in the sample is shortened for explanation purposes. The real value is longer, and it is the output of the SHA-256 algorithm on the previous invoice after encoding it in Base64. Your system computes it automatically and places it in position, and you do not write it by hand.
Why does the developer care about these two fields specifically? Because they are the two biggest sources of errors in a new integration. If your system restarts numbering from one after a server restart, the counter repeats and the chain breaks. And if you send two invoices in parallel without ordering, the hash values get mixed up. The practical rule: generate the counter and hash in a single sequential thread per issuing device, and do not allow two invoices to be issued at the same moment on the same path. This keeps the sequence intact and spares you the hardest validation errors of all.
Explaining the seller block (Supplier)
The cac:AccountingSupplierParty carries the identity of whoever issued the invoice. Its most important field is cbc:CompanyID inside cac:PartyTaxScheme, which is the 15-digit VAT registration number. This number must start and end with the digit 3, and must match your registration with the Authority, otherwise the invoice is rejected at clearance.
Field cbc:ID schemeID="CRN" carries the establishment’s commercial registration number. And the cac:PostalAddress block carries the national address: the street name, building number, district, city, postal code, and country code SA. These fields are mandatory in the standard invoice, and omitting any of them triggers a validation error.
Field cbc:RegistrationName inside cac:PartyLegalEntity carries the establishment’s legal name as it appears in the register. Write it in Arabic exactly as registered, and do not translate it. Here the value of the UTF-8 encoding we declared in the file header shows.
Explaining the buyer block (Customer)
The cac:AccountingCustomerParty resembles the seller block, but it describes who you buy from or sell to. In the standard invoice issued from establishment to establishment, the buyer must carry a valid tax registration number in cbc:CompanyID, because both parties are taxable, and the buyer will deduct input tax based on this invoice.
This difference is fundamental. In the standard invoice the buyer’s tax number is mandatory, whereas in the simplified invoice addressed to individuals it is not required because the individual does not deduct input tax. For the technical detail of individual invoices, see B2C Invoices for Individuals, Technically.
The buyer’s address here is a little simpler than the seller’s address, because some of its fields are optional in Phase Two. Even so, the country code, city name, and postal code remain elements we recommend completing to avoid validation notes and ensure the invoice’s clarity.
A practical point for the developer: do not assume the buyer is always an establishment. Build your integration so it reads the buyer type first, then decides whether to add the cac:PartyTaxScheme block or remove it. If you insert an empty or invalid tax number in an individual’s invoice, it may trigger an error instead of solving one. Flexibility in generating this block according to the party type is what distinguishes a mature integration from a fragile one.
Explaining the invoice line (Invoice Line)
Quantity × unit price = line net
Line net × 15% = tax
Net + tax = total
The cac:InvoiceLine is the heart of the invoice. Every item you sell becomes an independent line. In the sample there is one line, but you repeat this block for each additional item, increasing the value of cbc:ID by one. For deeper detail, see Invoice Lines in XML.
Field cbc:InvoicedQuantity carries the quantity, and the attribute unitCode in it specifies the unit of measure. The value PCE means “piece,” and there are other codes for kilogram, hour, and meter. And the field cbc:LineExtensionAmount carries the line net before tax, which is the product of quantity and unit price. In the sample: 10 units at SAR 100 yields SAR 1,000.
The cac:Item carries the item name and its tax classification. And the field cbc:ID inside cac:ClassifiedTaxCategory has the value S meaning “subject to the standard rate,” and the rate is 15%. This classification tells the Authority how the tax on this item is calculated. If the item were exempt the value would differ, and if it were zero-rated it would differ as well.
The cac:Price carries the price of a single unit in cbc:PriceAmount. Note the difference: the unit price is SAR 100, and the line net is SAR 1,000. The system verifies that the line net equals the quantity multiplied by the unit price, so any discrepancy triggers a calculation error in validation.
Explaining the totals block (Totals)
After the line items come two totals blocks. The first, cac:TaxTotal is at the level of the whole invoice, and carries the sum of tax distributed by tax category in cac:TaxSubtotal. Here the taxable base appears TaxableAmount with a value of SAR 1,000, the tax amount TaxAmount with a value of SAR 150, and the rate 15%.
The second block, cac:LegalMonetaryTotal is the final monetary totals. In it, TaxExclusiveAmount is the total before tax (SAR 1,000), andTaxInclusiveAmount is the total including tax (SAR 1,150), andPayableAmount is the amount payable (SAR 1,150). In an invoice with no discounts or prepayments, the total including tax equals the amount payable.
The golden rule in the totals block is exact matching. The sum of LineExtensionAmount for all lines must equal TaxExclusiveAmount, and the sum of taxes must equal TaxAmount in the invoice block. The most common validation error is a one-riyal discrepancy caused by wrong rounding. Compute the tax at the line level or at the invoice level in a unified way, and do not mix the two.
Let Qoyod generate the XML file on your behalf
Qoyod builds the entire standard invoice file, signs and stamps it through the Fatoora platform, and validates it before sending. You write the invoice, and the rest is automatic.
How to turn the sample into a simplified invoice (B2C)
The sample above is standard, issued from establishment to establishment. To turn it into a simplified tax invoice addressed to individuals, you change only specific elements, and the general structure stays the same.
The first change is in the header: the value of cbc:InvoiceTypeCode stays 388, but the attribute name changes from 0100000 to 0200000. The second position becomes 2, and it means the invoice is issued from an establishment to a consumer. This change alone shifts the invoice’s path from clearance to reporting.
The second change is in the buyer block: the buyer’s tax registration number is no longer mandatory, because the individual consumer does not deduct input tax. You can remove cac:PartyTaxScheme from the buyer block, and you may suffice with the buyer’s name or leave it generic.
The third change is fundamental to the path, not the file: the simplified invoice is not sent for clearance before it is handed over. You issue it and hand it to the buyer immediately, then report it to the Fatoora platform within 24 hours. The QR code also becomes mandatory and visible on the printed invoice, because the consumer uses it to verify. To understand the clearance and reporting mechanism in detail, see the clearance and reporting pages in the developer center.
Read the file top to bottom once
Before you modify the sample, practice reading it the way the validator reads it. Start from the XML declaration that specifies the version and encoding. Then the root element Invoice with its four namespaces. Then the empty extensions block that will carry the signature later. This order is not arbitrary, because the UBL standard requires the extensions to come first.
After that you pass through the header fields in order: the invoice number, then the unique identifier, then the date and time, then the invoice-type flag, then the currency. Then the counter and the hash. Each field in its specified position, and none may be brought forward ahead of another. Then you move to the seller, then the buyer, then the line items, then the totals. This path is the same one the validation system follows when it reads your file.
The benefit of this exercise is that you gain an intuition for where the error is before the validator tells you. If you see a line-items block before the buyer block, you immediately know the order is broken. And if you see a tax number that does not start with the digit 3, you anticipate a rejection in the identity. One careful read spares you many correction rounds later. Print the sample, mark each block with your pen, and link it to the corresponding explanation on this page.
Before you send: run the sample through validation
The sample is structurally valid, but structural validity is one thing and passing business rules is another. Before you send any invoice to production, run it through the Sandbox and through the validation rules the Authority applies. For the detail of these rules, see Validation Rules for the Invoice.
The errors that appear in validation are mostly three. The first is arithmetic: a discrepancy between the sum of the lines and the totals block due to rounding. The second is in the identity: a tax registration number that does not match the required format or does not start and end with the digit 3. The third is in the order: a block placed in the wrong position within the tree, such as putting the line items before the parties.
The practical rule: do not test directly on production. Start with the Sandbox using a test certificate, fix every note, then move to production with the actual CSID certificate. This protects you from accumulating rejected invoices in your official record.
Build the validation step as a permanent part of your integration, not a step you test once and forget. Make your system validate every invoice locally before sending it, and log the reason for any rejection clearly. Many teams discover that a single error in rounding or in the registration-number format repeats across hundreds of invoices because it was not caught early. A short validation loop at each issuance is far cheaper than correcting a whole batch after it is rejected.
The difference between this page and the structure and format pages
You may wonder when to use this page and when to use the explanation pages. The difference is in purpose. This page is practical: you copy the sample, modify it, and try it. The XML Invoice: The Technical Format page is a reference: it explains what the file is and how it is read. And the E-Invoice Structure page is analytical: it breaks the document into its three sections and explains how they nest.
The recommended order: read the structure page first to understand the sections, then the format page to understand the rules, then come back to this page to take the ready sample and apply what you understood. Three pages complement each other, each serving a different moment in your journey.
And if you want to make sure your file matches the official schema before anything else, the Invoice Schema and Its Validation page explains how the system validates the file against the approved schema.
How Qoyod handles generating the XML file on your behalf
Everything we explained on this page happens in Qoyod automatically. When you create an invoice in Qoyod, the system builds the UBL 2.1 file with all its blocks: the header, the parties, the line items, and the totals; it computes the ICV counter and the PIH hash; it orders the elements in the correct tree; it signs and stamps the invoice through the Fatoora platform; and it validates it before sending.
This means you do not write a single line of XML in daily operation. You write the invoice data in a simple interface, and Qoyod turns it into a file compliant with Phase Two. The sample on this page helps you if you are building a custom integration or testing, but in normal use Qoyod spares you the entire technical burden.
Qoyod is compliant with Phase Two of e-invoicing, manages the CSID certificate automatically, stores the hash chain for verification, and provides technical support 24 hours a day, seven days a week. This way you focus on your business, and the system handles technical compliance on your behalf.
Frequently asked questions
Is the sample on this page ready to send to production directly?
No. The sample is structurally valid and ready to copy and modify, but it carries illustrative data and shortened stamp values. Replace the seller, buyer, and line-item data with your actual data, then run it through the Sandbox and the validation rules, and let your system generate the signature and stamp before sending.
Why are the cryptographic stamp and QR code values shortened in the sample?
Because these values are computed automatically on the content of the invoice itself at issuance time using a CSID certificate. They are not written by hand and are not copied from another invoice. The sample shows their placement in the file only, and the final value is generated by the system.
What is the fundamental difference between the standard and simplified samples?
The standard is issued from establishment to establishment, carries the tax number of both parties, and is subject to clearance before delivery. The simplified is addressed to individuals, does not require the buyer’s tax number, and is delivered immediately then reported within 24 hours. The change in the file starts from the invoice-type flag in the header.
Should I write the names in Arabic inside the file?
Yes, write the establishment name and the item name in Arabic exactly as registered with the Authority. This is why the file encoding must remain UTF-8, as it is the encoding that carries Arabic characters without corruption.
What do I do if validation rejects my invoice because of a one-riyal discrepancy?
This is a rounding error. Make sure you compute the tax in a unified way, either at each line level then sum, or at the whole-invoice level, without mixing. And make sure the sum of the line nets equals the total before tax in the totals block.
Do I need to write XML by hand if I use Qoyod?
No. In daily use you write the invoice data in the Qoyod interface, and the system builds the file, signs it, validates it, and sends it. This sample is useful for developers building a custom integration or testing, not for daily operation.