Published · 31 August 2026 · 10 min read
ZATCA XML Invoice Structure: UBL 2.1 Fields Explained
A field-by-field walkthrough of the UBL 2.1 XML schema used by ZATCA Phase 2: namespaces, mandatory fields, invoice vs debit note vs credit note, line items, tax totals, and common validation errors.
Every ZATCA Phase 2 invoice is, mechanically, an XML document. Specifically, a UBL 2.1 document with a Saudi ZATCA extension namespace, signed with ECDSA, and POSTed to the Fatoorah endpoint. This page is the developer reference: which fields are required, what values they take, and what Fatoorah does when you get them wrong. For the high-level picture of Phase 2, see our complete Phase 2 guide; for the onboarding flow, see the onboarding step-by-step.
Throughout this page, an example invoice for "Al-Noor Trading Co." (a fictional Saudi retailer) is used. The example is for a single-line-item B2B invoice, which is the most common shape.
The namespace stack
A ZATCA XML invoice carries four namespaces. ZATCA requires them in this exact order — Fatoorah validates the order strictly:
<?xml version="1.0" encoding="UTF-8"?>\n<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"\n xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"\n xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"\n xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"\n xmlns:sig="urn:oasis:names:specification:ubl:dsig:xsd:CommonSignatureComponents-2"\n xmlns:sbc="urn:oasis:names:specification:ubl:schema:xsd:SignBasicComponents-2"\n xmlns:ds="http://www.w3.org/2000/09/xmldsig#">\n ...\n</Invoice>
Two namespaces are added by ZATCA on top of standard UBL 2.1: the sig / sbc pair for the digital signature, and the ds namespace for the W3C XML-Signature standard. The signing logic is in our cryptography guide; for now, all you need to know is that every invoice has a <Signature> block as the first child of <Invoice>.
The root element: UBLVersionID, ID, IssueDate, IssueTime
The first four elements of every ZATCA invoice are non-negotiable:
<cbc:UBLVersionID>— fixed value 2.1. Do not put "2.0" or "2.2" here. Fatoorah rejects 2.0 outright.<cbc:ID>— your invoice number. Pattern: free text, max 100 characters, must be unique per device. Convention is to use your ERP document number (e.g.INV-2026-0815-0042). Do not include any spaces or special characters that XML would escape.<cbc:IssueDate>— ISO 8601 date format:2026-08-31. Hijri dates are not accepted here; Fatoorah requires Gregorian.<cbc:IssueTime>— ISO 8601 time:14:23:45Z. The Z suffix is UTC. If you are in Arabia time (UTC+3), convert before sending. Fatoorah will reject a Riyadh local time.
Example header block:
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>\n<cbc:ID>INV-2026-08-31-0042</cbc:ID>\n<cbc:IssueDate>2026-08-31</cbc:IssueDate>\n<cbc:IssueTime>11:23:45Z</cbc:IssueTime>\n<cbc:InvoiceTypeCode name="0211010">388</cbc:InvoiceTypeCode>\n<cbc:DocumentCurrencyCode>SAR</cbc:DocumentCurrencyCode>\n<cbc:TaxCurrencyCode>SAR</cbc:TaxCurrencyCode>
Two notes. First, the InvoiceTypeCode is a fixed value — 388 for a standard tax invoice. ZATCA has ~10 other type codes (381, 383, 386, etc.) for credit notes, debit notes, and simplified tax invoices. You will use 388 for 95% of your invoices. Second, you can invoice in a foreign currency (USD, EUR) but the VAT must be in SAR. The DocumentCurrencyCode and TaxCurrencyCode can differ; Fatoorah handles the conversion at the official SAMA rate.
The supplier and customer blocks (cac:AccountingSupplierParty / cac:AccountingCustomerParty)
These two blocks describe the seller and the buyer. Each has three sub-elements: party identification, postal address, and tax scheme. The seller block is always required; the customer block is required for B2B invoices and may be omitted for B2C.
For the seller (your company), ZATCA requires three identifiers in the party ID block:
- VAT number: 15 digits, no dashes or spaces, with
schemeID="VAT". - Commercial Registration (CR) number: 10 digits, with
schemeID="CRN". ZATCA validates this against the Ministry of Commerce database. - MHRSD national number (optional but recommended): 7 digits, with
schemeID="MHR". This is the company establishment number from the Ministry of Human Resources.
<cac:AccountingSupplierParty>\n <cac:Party>\n <cac:PartyIdentification>\n <cbc:ID schemeID="VAT">300012345600003</cbc:ID>\n </cac:PartyIdentification>\n <cac:PartyIdentification>\n <cbc:ID schemeID="CRN">1010111222</cbc:ID>\n </cac:PartyIdentification>\n <cac:PostalAddress>\n <cbc:StreetName>King Fahd Road</cbc:StreetName>\n <cbc:BuildingNumber>4321</cbc:BuildingNumber>\n <cbc:CityName>Riyadh</cbc:CityName>\n <cbc:PostalZone>12345</cbc:PostalZone>\n <cac:Country>\n <cbc:IdentificationCode>SA</cbc:IdentificationCode>\n </cac:Country>\n </cac:PostalAddress>\n <cac:PartyTaxScheme>\n <cbc:RegistrationName>Al-Noor Trading Co.</cbc:RegistrationName>\n <cbc:CompanyID schemeID="VAT">300012345600003</cbc:CompanyID>\n <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>\n </cac:PartyTaxScheme>\n <cac:PartyLegalEntity>\n <cbc:RegistrationName>Al-Noor Trading Co.</cbc:RegistrationName>\n </cac:PartyLegalEntity>\n </cac:Party>\n</cac:AccountingSupplierParty>
The customer block is identical in structure but the VAT number and CR are the buyer’s, not yours. For B2C sales, you can omit AccountingCustomerParty entirely; Fatoorah will accept the invoice and treat it as a consumer sale.
The tax total block (cac:TaxTotal)
There are two TaxTotal blocks. The first is the document-level total (the sum of all line-level tax), the second is the invoice total in words for printed PDFs.
<cac:TaxTotal>\n <cbc:TaxAmount currencyID="SAR">150.00</cbc:TaxAmount>\n <cac:TaxSubtotal>\n <cbc:TaxableAmount currencyID="SAR">1000.00</cbc:TaxableAmount>\n <cbc:TaxAmount currencyID="SAR">150.00</cbc:TaxAmount>\n <cac:TaxCategory>\n <cbc:ID>S</cbc:ID> <!-- Standard rate -->\n <cbc:Percent>15.00</cbc:Percent>\n <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>\n </cac:TaxCategory>\n </cac:TaxSubtotal>\n</cac:TaxTotal>\n\n<cac:LegalMonetaryTotal>\n <cbc:LineExtensionAmount currencyID="SAR">1000.00</cbc:LineExtensionAmount>\n <cbc:TaxExclusiveAmount currencyID="SAR">1000.00</cbc:TaxExclusiveAmount>\n <cbc:TaxInclusiveAmount currencyID="SAR">1150.00</cbc:TaxInclusiveAmount>\n <cbc:AllowanceTotalAmount currencyID="SAR">0.00</cbc:AllowanceTotalAmount>\n <cbc:PayableAmount currencyID="SAR">1150.00</cbc:PayableAmount>\n</cac:LegalMonetaryTotal>
Three things trip up first-time integrators. First, the standard VAT rate in Saudi is 15%. Do not assume it from the EU or the US. Second, the document total is the sum of all line-level tax amounts, not a single line; this matters for multi-rate or zero-rated lines. Third, PayableAmount is what the buyer pays in total — it is line extension plus tax, less any allowance or discount.
Line items (cac:InvoiceLine)
Each line on the invoice is a cac:InvoiceLine. The minimum is:
<cac:InvoiceLine>\n <cbc:ID>1</cbc:ID>\n <cbc:InvoicedQuantity unitCode="PCE">10</cbc:InvoicedQuantity>\n <cbc:LineExtensionAmount currencyID="SAR">1000.00</cbc:LineExtensionAmount>\n <cac:Item>\n <cbc:Name>Samsung 55-inch LED TV</cbc:Name>\n <cac:SellersItemIdentification>\n <cbc:ID>SKU-TV-55-001</cbc:ID>\n </cac:SellersItemIdentification>\n <cac:ClassifiedTaxCategory>\n <cbc:ID>S</cbc:ID>\n <cbc:Percent>15.00</cbc:Percent>\n <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>\n </cac:ClassifiedTaxCategory>\n </cac:Item>\n <cac:Price>\n <cbc:PriceAmount currencyID="SAR">100.00</cbc:PriceAmount>\n </cac:Price>\n <cac:TaxTotal>\n <cbc:TaxAmount currencyID="SAR">150.00</cbc:TaxAmount>\n <cac:TaxSubtotal>\n <cbc:TaxableAmount currencyID="SAR">1000.00</cbc:TaxableAmount>\n <cbc:TaxAmount currencyID="SAR">150.00</cbc:TaxAmount>\n <cac:TaxCategory>\n <cbc:ID>S</cbc:ID>\n <cbc:Percent>15.00</cbc:Percent>\n <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>\n </cac:TaxCategory>\n </cac:TaxSubtotal>\n </cac:TaxTotal>\n</cac:InvoiceLine>
The line extension must equal quantity × unit price, before discount, before tax. The line tax must equal line extension × tax rate. These two constraints are checked by Fatoorah. A 0.01 SAR rounding error at the line level will fail validation.
Invoice, debit note, and credit note
ZATCA uses three document types in Phase 2:
- 388 — Tax Invoice (B2B / standard). The default. Use this for every sale to a VAT-registered business.
- 381 — Credit Note. A refund. References the original invoice in a
<cac:BillingReference>block. Fatoorah will not accept a credit note without the original invoice number. - 383 — Debit Note. An additional charge against an existing invoice. Same referencing rules as credit note.
A simplified tax invoice (type 386, 387, 388 sub-codes) is for B2C. It is functionally the same document with less customer information. Fatoorah routes simplified invoices to the reporting endpoint (B2C), not clearance (B2B).
The clearance hash and previous-invoice hash
The two fields that bind your invoice series together cryptographically. Fatoorah returns a clearance hash (SHA-256 hex string, 64 chars) and a sold-to counter when it accepts your invoice. You must include the clearance hash on the printed PDF the customer receives, and you must include the previous clearance hash as a <cbc:PrecedingInvoiceHash> field in the next invoice in your series. The full chain mechanic is in our cryptography guide; for now, the practical advice is: store the clearance hash with the invoice, and never skip a counter.
Common validation errors and how to fix them
The top five errors you will see on day one:
- "Hash mismatch". Your chain hash is computed from a different previous invoice than Fatoorah thinks is the last. Fix: read the last clearance hash from your own store, do not trust your ERP’s “last invoice” field.
- "Counter must be sequential". You skipped a number. Fix: switch to UUID-based counters.
- "VAT rate invalid". You sent 14% or 16%. Fix: hard-code 15% (the only standard rate; reduced rates and zero-rates use a different category code).
- "Seller VAT number not found". Typo or trailing space. Fix: read the VAT number directly from the Fatoorah profile, never from a copy-paste.
- "Signature invalid". The ECDSA signature does not match the canonicalized XML. Fix: ensure your XML canonicalization is C14N (the W3C default), and that you sign the canonicalized bytes, not the pretty-printed bytes.
Frequently asked questions
Can I reuse fields from my existing ERP invoice template?
Only after you validate the values. ERP invoice numbers, dates, and line amounts are usually compatible; party IDs (VAT, CR) almost always need re-formatting. Run the sandbox validation on ten real invoices before trusting any template.
Do I send the XML in the request body or as a multipart upload?
Request body, Content-Type: application/xml. Fatoorah does not support multipart for invoices. The signed XML is the entire payload.
What if my ERP can only produce JSON, not XML?
You need a thin adapter layer. Most modern stacks (Node, Python, .NET, Java) have mature libraries that produce UBL 2.1 from a higher-level representation. Do not write a string template; use a schema-validated generator.
How do I test without real production data?
Use the Fatoorah sandbox (sandbox-fatoorah.zatca.gov.sa) with a real VAT number, but on a parallel set of test invoices. The sandbox never talks to production, so you can run 1,000 test invoices without any tax consequences.
Related tools
See all →Related guides
See all guides →-
31 Aug 2026 · 7 min read
ZATCA Phase 2 (Fatoorah): The Complete 2026 Guide for Saudi Businesses
-
31 Aug 2026 · 8 min read
ZATCA Fatoorah Onboarding: Step-by-Step for SMEs (2026)
-
31 Aug 2026 · 12 min read
ZATCA ECDSA Cryptographic Stamping Explained (in Plain English)
-
31 Aug 2026 · 12 min read
ZATCA Phase 2 Waves & Deadlines: 2026 Compliance Calendar
-
25 Jul 2026 · 1 min read
ZATCA Phase 1 vs Phase 2: What Changes for Your Business
Related articles
References
Primary sources used in this guide:
Get the next Saudi finance guide
One short email per month with a new Saudi finance guide, calculator update, or ZATCA tip. No spam, unsubscribe anytime.
Create your ZATCA tax invoice with QR
Add your 15-digit VAT number, totals, and download a Phase 1 compliant PDF — free, online, no signup.