ZATCA clearance vs. reporting: the distinction most Odoo setups get wrong
Clearance and reporting are not two names for the same ZATCA Phase 2 workflow. They're two different processes with different timing, different invoice types, and different failure modes — and conflating them is the most common reason e-invoicing integrations misfire.
- Published
- 14 May 2026
- Updated
- 04 Aug 2026
- Reading time
- 4 min
- Tags
- ZATCA · Odoo · e-invoicing · Saudi Arabia · compliance
Every time I sit down with a client migrating to ZATCA Phase 2, the first thing I have to untangle isn't code — it's vocabulary. "Clearance" and "reporting" get used interchangeably in conversation, in Slack threads, sometimes even in scope documents. They are not interchangeable. They're two distinct regulatory processes, they apply to different invoice types, and a system that handles one correctly but assumes it also covers the other will pass testing and then fail in production the first time it hits a real invoice on the wrong path.
The two processes, precisely
ZATCA Phase 2 — the "Integration Phase" — splits e-invoicing into two tracks based on who the invoice is for.
Clearance applies to B2B standard tax invoices. These are invoices issued to another VAT-registered business. The rule is strict and sequential: the invoice must be generated, cryptographically signed, and submitted to ZATCA's clearance API before it can be legally issued to the buyer. ZATCA validates the invoice, stamps it with its own cryptographic signature, and returns the cleared document. Only that cleared version — the one carrying ZATCA's stamp — is the legal invoice. If your system generates a PDF and hands it to the customer before that round trip completes, you've issued an invoice that isn't actually valid, regardless of how correct the numbers on it are.
Reporting applies to B2C simplified tax invoices — the ones issued to a consumer rather than a registered business, the kind you'd hand over at a retail counter or a restaurant table. Here the sequence is reversed. The invoice is generated and issued to the buyer immediately, with no pre-clearance step, because retail transactions can't wait on a real-time API round trip at the point of sale. Instead, the invoice must be reported to ZATCA within 24 hours of issuance. The compliance obligation is retrospective, not gating.
That's the whole distinction in one sentence: clearance gates issuance, reporting follows it. Get the direction backwards for either invoice type and you're non-compliant even if every field on the invoice is correct.
Why the cryptographic stamp matters here
Both flows depend on a chain of cryptographic requirements set up well before the first invoice goes out — a compliance CSID (Cryptographic Stamp Identifier) issued by ZATCA, a signed invoice hash, and for cleared invoices, ZATCA's own stamp layered on top after clearance. The QR code printed on the invoice isn't decorative; it encodes seller details, VAT number, timestamp, invoice total, VAT amount and, for cleared invoices, the cryptographic stamp itself, in a TLV-encoded, Base64-wrapped format that ZATCA's own verification tooling and any buyer's app can decode and check.
This is where a lot of integrations quietly go wrong. It's entirely possible to generate a QR code that looks right — right size, right position on the invoice layout, scannable — while encoding the wrong data or, worse, encoding data from the pre-clearance draft rather than the cleared, stamped version. A QR code on a B2B invoice that doesn't carry ZATCA's post-clearance stamp isn't a formatting bug; it's evidence the invoice was issued before clearance completed, which is the exact violation the phase exists to prevent.
Where Odoo implementations misconfigure this
Odoo's ZATCA modules (whether the official Enterprise localization or a custom build) generally model the two flows correctly at the architecture level — there's a decision point that routes an invoice down the clearance path or the reporting path based on whether the buyer is a registered business. The misconfiguration tends to show up in three places:
Invoice type classification. The B2B/B2C determination often keys off whether a VAT number is populated on the customer record, not off actual invoice content or contract terms. A B2B customer with an empty or malformed VAT field on their partner record can silently fall through to the B2C reporting path — which means a standard tax invoice that should have been cleared before issuance gets treated as a simplified invoice and reported after the fact instead. That's a compliance gap that won't show up until an audit, because the invoice still goes out and still gets a QR code — just the wrong kind.
Down payment and installment invoices. These are consistently the trickiest case, because a down payment invoice against a B2B contract is still a B2B document and still needs clearance, but numbering and sequencing rules for partial invoices don't always map cleanly onto the standard invoice numbering scheme ZATCA expects. I've seen this exact failure mode on a live implementation: the down payment invoice numbering didn't satisfy ZATCA's sequencing rules, which put every down payment invoice at risk of failing clearance even though the underlying invoice content was correct.
Treating the API call as fire-and-forget. Clearance is synchronous by design — you submit, you wait for ZATCA's response, and only the cleared response is the real invoice. Implementations that treat the clearance call like a webhook notification (submit and move on, reconcile status later) end up in a state where the ERP thinks an invoice is issued and the regulator has no record of clearing it, or worse, the system re-issues a "corrected" version without properly handling the credit note process ZATCA requires for amendments.
The practical fix
None of this requires exotic tooling — it requires treating clearance-vs-reporting as a routing decision that has to be verified on real data, not assumed from the module's default configuration. In practice that means auditing actual invoice records against actual buyer VAT status rather than trusting the field to be populated correctly, testing the down-payment and credit-note paths specifically rather than only the standard invoice happy path, and building the integration so a failed clearance call blocks issuance rather than degrading to "issue anyway, retry later."
The regulatory language sounds abstract until an invoice fails clearance in front of a customer, or an audit turns up a batch of B2B invoices that were reported instead of cleared. Getting the distinction right at the architecture stage is a lot cheaper than reconciling it after go-live.
Have a system that needs to work in production?
Tell me what's breaking — or what you're building.