Skip to content
Z
← Back to blog

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.

ZATCA XML invoice structure UBL 2.1 guide cover showing XML code snippet with Invoice, ID, IssueDate, TaxTotal tags highlighted

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:

  1. "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.
  2. "Counter must be sequential". You skipped a number. Fix: switch to UUID-based counters.
  3. "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).
  4. "Seller VAT number not found". Typo or trailing space. Fix: read the VAT number directly from the Fatoorah profile, never from a copy-paste.
  5. "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.

See all →
See all guides →

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.

I agree to receive marketing emails from this site. You can unsubscribe at any time.

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.

Open the generator