# ZATCA E-Invoicing — Restaurant Manager Workbook (version 7.0.0)

This document describes what the workbook does for ZATCA e-invoicing, and
what a vendor must implement to plug in as a Phase 2 provider.

**The short version:** the workbook does Phase 1 fully and prepares Phase 2
offline. It never sends anything to the tax authority. Live submission needs
a ZATCA-approved e-invoicing provider of the restaurant's choice.

This document is not tax advice and not a ZATCA publication. Confirm the
current rules with ZATCA or your accountant.

## Phase 1 — what the app does

Phase 1 (the QR-code phase) is complete in the workbook and needs no
provider, no internet and no setup beyond the business details in Settings.

### Every issued invoice carries

- **A TLV QR code, base64-encoded**, printed on the invoice. The five TLV
  fields are the standard ones: seller name, VAT registration number,
  invoice date and time, invoice total including VAT, and VAT amount.
  Example from the demo data (invoice INV-00001, demo data only): seller
  "ABC Grill & Mandi", VAT number 300000000000003, 2026-11-04T17:11:00+03:00,
  total 14.38, VAT 1.88.
- **A UUID** (universally unique identifier) for the invoice.
- **A hash chain.** Each invoice stores the hash of the previous invoice
  (`prevHash`) and its own hash, computed from the UUID, previous hash, date,
  time, total and VAT amount (SHA-256). The chain makes the invoice sequence
  checkable: a missing or altered invoice breaks it.
- **A frozen snapshot.** Once issued, the invoice's numbers never change,
  even if recipe prices or ingredient costs change later. The QR code, UUID
  and hash all come from that frozen snapshot.

### What the app checks

The Controls check `zatcaReady` verifies, for every issued invoice and
credit note, that the Phase 1 fields are present, the Phase 2 XML is valid,
the hash chain is intact, and no submission is Queued, Failed or Rejected.
Any gap is listed with the document number.

### What Phase 1 does not do

Phase 1 does not send anything anywhere and does not need clearance. The QR
code is for the customer and for checking — it is not a submission.

## Phase 2 — what the app prepares offline

### The XML

For each issued invoice or credit note the workbook can generate a
**simplified UBL 2.1 XML** document, built only from the frozen invoice
snapshot, so the XML always matches the issued invoice. It contains:

- UUID and previous-invoice hash (as document references);
- TLV QR data;
- seller (name, VAT number, CR number, address, city, country SA) and buyer;
- invoice lines with quantities, prices and VAT category;
- VAT breakdown and totals;
- credit notes use document type **381** with a billing reference to the
  original invoice.

**Honest limit: this is simplified UBL, not certified ZATCA XML.** The
workbook validates it offline for well-formedness and required fields only.
Full schema compliance and clearance are the provider's check. A provider
that finds the XML invalid must say so in plain words (see "Errors" below),
and the workbook records the submission as Failed — it never marks the
invoice cleared on a bad XML.

View or download the XML per invoice from the invoice view.

### Submission status

Each invoice and credit note has one status, kept in the `einvSubmissions`
table and shown in the invoice view and in Settings → E-invoicing:

| Status | Meaning |
| --- | --- |
| Not submitted | Nothing has been sent. The default. |
| Queued | The provider could not be reached, or this build does not send. **Not submitted.** Retry is offered. |
| Submitted | Sent to the provider, waiting for clearance. |
| Accepted | The provider accepted it **and returned a submission reference**. This is the only status that counts as cleared. |
| Rejected | The provider refused it, with a reason. |
| Failed | The provider returned an error, or the XML did not validate. |
| Cancelled | Cancelled with the provider (only if the provider supports it). |

**Only "Accepted with a submission reference" counts as cleared.** Nothing
else — not Submitted, not Queued, not a successful network call — clears an
invoice.

### The provider registry

Providers are managed in **Settings → E-invoicing**. Each provider record
holds:

| Field | Meaning |
| --- | --- |
| `name` | Display name, for example "My e-invoicing provider". |
| `baseUrl` | API base URL (`http://` or `https://`). |
| `submitEndpoint` | Submission endpoint: a path starting with `/` or a full `http(s)` address. |
| `statusEndpoint` | Status endpoint, same format. |
| `authType` | One of: API key, OAuth 2.0, Basic auth, Certificate. |
| `credRef` | A short **label** saying which credential to use — never the secret itself. The form rejects anything that looks like a pasted secret key (a long string with no spaces). |
| `supportsCancel` | Whether the provider offers cancel / void. The workbook only offers Cancel when this is on. |

**"Manual / offline"** is the default provider and preserves today's
behaviour: nothing is sent. A provider can only be removed when it is not
the active one.

### How submission works in this build

The workbook has one provider interface with three adapters:

- **Manual** — nothing is sent, nothing is recorded as submitted.
- **Mock** — an offline stand-in for testing only, driven by a chosen
  outcome (accept / submitted / reject / fail / unreachable). It never
  touches a network.
- **HTTP** — a real provider. **This build never fetches**, so a submit
  through an HTTP provider is recorded as **Queued, not sent**, with the
  message that live submission needs a connected provider.

That is deliberate: this release prepares everything and queues it. Wiring a
real provider's network calls is a separate, explicit step for the
restaurant's chosen approved provider — it must not happen silently.

A submission with no provider at all returns a plain message naming the
Settings step, and records nothing. A submission for a document with no
frozen invoice, or with missing Phase 1 fields, is refused with a plain
message.

## What a vendor must implement

This section is the contract for a ZATCA-approved provider (or its
integrator) that wants the workbook to submit through it. The same text
appears in the app's Guide under "E-invoicing providers — what a provider
must implement".

### 1. Receive an invoice

One submission call to the submission endpoint, carrying the Phase 2 XML for
**one** invoice or credit note, plus the invoice number, UUID and totals.

It must answer with:

- a **submission reference** (an ID the workbook can use later to ask about
  this submission), and
- one status: **Submitted, Accepted, Rejected or Failed**.

A submission with no reference cannot count as Accepted, even if the
provider says it went through.

### 2. Report the status

One status call to the status endpoint that takes a submission reference and
returns:

- the current status (one of: Not submitted, Queued, Submitted, Accepted,
  Rejected, Failed, Cancelled), and
- when rejected, a short reason in plain words.

The workbook polls this when the user asks to check a submission. It updates
the stored status only when the returned status differs.

### 3. Cancel / void (optional)

If the provider supports it, a cancel call that takes a submission reference
and returns **Cancelled**. The workbook only offers Cancel when the provider
record says it supports it.

Cancelling a submission is not the same as voiding the invoice in the books:
to void an issued invoice, the restaurant still issues a credit note.

### 4. Log in (auth)

One of: **API key, OAuth 2.0, Basic auth, or a certificate**. The workbook
stores only a short label saying which credential to use. The secret itself
stays with the provider or in the restaurant's password manager and is never
typed into the workbook file.

### 5. Errors

Every failure must come back with a **short plain-language reason** — for
example "totals do not match" or "provider unreachable" — so the invoice can
be queued with a clear "not submitted" status and retried. A failure must
never be reported in a way that could be read as success, and a failed or
rejected document must never be marked cleared.

### 6. What the workbook sends

Only the frozen invoice data: seller and buyer names, lines, VAT breakdown
and totals, UUID, previous-invoice hash and QR data. **No salary, stock or
other business data is ever sent.**

### Summary table

| What the provider does | What it must accept / return |
| --- | --- |
| Receive an invoice | One submission call carrying the Phase 2 XML for one invoice or credit note, plus invoice number, UUID and totals. Returns a submission reference and one status: Submitted, Accepted, Rejected or Failed. |
| Report the status | One status call taking a submission reference. Returns the current status and, when rejected, a short reason in plain words. |
| Cancel / void (optional) | A cancel call taking a submission reference, returning Cancelled. |
| Log in (auth) | API key, OAuth 2.0, Basic auth, or certificate. Only a label is stored in the workbook. |
| Errors | Every failure with a short plain-language reason, so the invoice can be queued as "not submitted" and retried — never silently marked cleared. |
| What the workbook sends | Only the frozen invoice data. No salary, stock or other business data. |

## What the workbook does not do

- It does not submit to ZATCA directly, and it does not claim to.
- It does not generate certified ZATCA XML.
- It does not store provider secrets.
- It does not send any data except the frozen invoice data, and only to the
  provider the restaurant chose, through the interface above.
