# How Saudi e-invoicing works

What the Saudi package stamps on every confirmed invoice, what the e-invoicing module adds, standard and simplified invoices, the invoice chain, the three API modes, when sending happens and what gets locked.

For a company in Saudi Arabia, every confirmed customer invoice and credit note is a tax invoice for ZATCA, the Zakat, Tax and Customs Authority. Creating, confirming and paying an invoice are explained in [Customer invoices](/docs/customer-invoices).

## Two phases {#two-phases}

**Phase 1** comes with the Saudi accounting package, the company's **Package** in [Accounting settings](/docs/accounting-start-here/accounting-settings). On every confirmed customer invoice and credit note it stamps the **ZATCA Issue Date** (tab **Other Info**: the invoice date at the current Riyadh time), fills an empty **Delivery Date** with the invoice date, and prints the Saudi layout: **Tax Invoice** or **Simplified Tax Invoice**, the VAT of each line, the totals with and without VAT, the **Supply Date**, and a QR code with the seller, its VAT number, the issue time, the total and the VAT. An invoice dated after today in Riyadh is refused, and the PDF of a confirmed invoice cannot be deleted.

**Phase 2** is this module. Each sales journal is connected to ZATCA once ([Connect a sales journal to ZATCA](connect-a-sales-journal-to-zatca)); from then on every invoice, credit note and debit note confirmed in it becomes a signed XML file (UBL 2.1) sent to ZATCA. The module ticks **ZATCA (Saudi Arabia)** under **Electronic Data Interchange** in the **Advanced Settings** tab of every Saudi sales journal, and no invoice of such a journal can be confirmed before the journal is connected.

## Standard and simplified invoices {#standard-simplified}

The client decides, through **Person** or **Company** at the top of the contact form:

| Client | Invoice | What ZATCA does | QR code on the PDF |
|---|---|---|---|
| **Company** | Standard (B2B) | Clears it: checks it, stamps it and returns it | Returned by ZATCA with the cleared invoice |
| **Person** | Simplified (B2C) | Receives a report of it | Built and signed by Jaah when the invoice is sent |

## The journey of an invoice {#journey}

**Confirm** first checks what ZATCA requires (connected journal, company VAT number and address, a tax on every line, no future date, the client's identification, the reason of a credit or debit note) and refuses with the list of what is missing. The confirmed invoice then shows **Electronic invoicing**: **To Send**. A background job builds the XML, signs it with the company's key and the journal's certificate and sends it; ZATCA's answer turns the invoice to **Sent**, or leaves it **To Send** with a banner and a note in the chatter. What each answer means and what to do: [Send an invoice to ZATCA](send-an-invoice-to-zatca).

## The chain {#chain}

ZATCA reads the invoices of a journal as a chain: each carries a counter and the fingerprint of the previous one. An invoice that got no answer keeps its place, and the next invoices of the same journal wait behind it with **Blocking Invoice**. A rejected invoice leaves the chain and takes a new place when it is sent again. Connecting a journal again starts its chain over.

## The three API modes {#modes}

**Sandbox** is ZATCA's shared test environment, **Simulation (Pre-Production)** a test environment of the company's own, **Production** the live one, where every accepted invoice counts in the VAT liability. The mode belongs to the company, and changing it disconnects all its journals.

## When sending happens {#when}

The scheduled action **EDI: Perform web services operations** sends the waiting invoices, twenty per run, and starts again while some remain.

- **When:** right after every confirmation, and once a day. **Process now** on the invoice, or **To ZATCA** in the **Send** dialog, sends one at once.
- **How to stop it:** an administrator deactivates it among the scheduled actions of the technical menu; invoices then stay **To Send** until **Process now**. A rejected invoice is never retried by the job: it waits for **Retry**.

## What gets locked {#locked}

- No cancellation at ZATCA: **Request EDI Cancellation** never appears on a Saudi invoice. A credit note corrects an invoice.
- In **Production**, an accepted invoice cannot be reset to draft, and after the first one the mode can no longer change. In every mode, an invoice that got no answer cannot be reset to draft until it gets one.
- The PDF made after acceptance and a rejected XML cannot be deleted.

## What the module adds to other screens {#other-screens}

- Addresses in Saudi Arabia: **Building Number**, **Plot Identification** and the district on the second street line; **Identification Scheme** and **Identification Number** (commercial registration, national ID, Iqama and others), printed under the address on the PDF.
- Taxes (**Accounting/Configuration/Accounting/Taxes**): **Exemption Reason Code** on 0% sales taxes, filled by the Saudi chart, and **Is Retention** on negative sales taxes (withholding). The default taxes are in [Set the default taxes](/docs/accounting-start-here/set-the-default-taxes).

## Who may do what {#access}

| Access | Can |
|---|---|
| **Administrator** role with **Administrator** on Accounting | The API mode in the settings; **Onboard**, **Renew** and **Re-Onboard** on the journal's **ZATCA** tab |
| **Administrator** on Accounting | Journals and taxes |
| **Invoicing** on Accounting | Confirm, **Process now**, **Retry**, credit and debit notes |
| Developer mode | The **EDI Documents** tab, with **Download** of an XML in error |

## What it does not do {#not-covered}

It does not touch vendor bills, does not send the invoice to the client ([Customer invoices](/docs/customer-invoices)) and does not file the VAT return: the tax figures of a period are read in the tax report of [Accounting reports](/docs/accounting-reports/prepare-the-tax-and-period-end-figures).

---

- Source: https://jaah.app/docs/e-invoicing-zatca/how-saudi-e-invoicing-works
- Updated: 2026-10-23
- Version: E-invoicing (ZATCA) 19.0.0.3
