/projects/zatca-aorabooks
2024–2026
ZATCA e-invoicing for Aorabooks — compliance at the counter
- client:
- Aorabooks tenants selling in Saudi Arabia
- role:
- Technical Project Manager
- Laravel
- Vue.js
- MySQL
01 — the problem
What was actually at stake
ZATCA Phase 2 made cryptographically signed, QR-coded e-invoices mandatory for Saudi businesses — with a fine schedule for getting it wrong. Aorabooks tenants needed compliance built in, not bolted on, and multi-tenancy made it harder: every tenant has its own certificates, its own invoice chain, its own clearance state.
And the counter is hostile territory — printers jam, networks drop mid-sale. Compliance could never be allowed to stop a till.
02 — the architecture
How it was built
ZATCA lives as its own bounded service: UBL 2.1 XML generation, per-tenant invoice hash chains, digital signing, TLV QR payload assembly, and submission to the clearance API. The design rule that mattered most: sign locally, print immediately with the QR, and run clearance through a retry ledger — a ZATCA outage queues re-clearance instead of blocking sales.
Receipts print over ESC/POS to thermal printers with cash drawers on the same circuit; every invoice stores its full compliance artifact trail (XML, hash, signature, response) so an audit eight months later is answered from the ledger.
- compliance
- ZATCA Phase 2 — UBL, hash chain, signing, QR, clearance
- tenancy
- per-tenant certificates & invoice chains
- resilience
- sign locally → print now → clear via retry ledger
- hardware
- thermal printers (ESC/POS), cash drawers
03 — the visuals
What it looks like
screenshot pending (NDA-safe crop)
drop /public/images/projects/zatca-aorabooks/01.jpg · 1600×900 · see docs/images.md
screenshot pending (NDA-safe crop)
drop /public/images/projects/zatca-aorabooks/02.jpg · 1600×900 · see docs/images.md
04 — from the codebase
ZATCA invoice clearance with a retry ledger
public function clear(Invoice $invoice): ClearanceResult
{
$xml = $this->ubl->render($invoice); // UBL 2.1 document
$signed = $this->signer->sign($xml); // XAdES B-B signature
$qr = $this->qr->payload($invoice, $signed); // TLV base64 for receipt
try {
$response = $this->zatca->clearance($signed);
$invoice->compliance()->create([
'status' => 'cleared',
'uuid' => $response->uuid,
'qr' => $qr,
]);
} catch (ZatcaUnavailable $e) {
// Never block the till: queue for re-clearance, print with QR now.
RetryClearance::dispatch($invoice)->backoff([60, 300, 900]);
$invoice->compliance()->create(['status' => 'queued', 'qr' => $qr]);
}
return new ClearanceResult($qr);
}05 — the outcome
What the numbers say
- of invoices signed & QR-coded at print time
- 100%
- sales blocked by clearance outages
- 0
- artifact trail per invoice, audit-ready
- full
Checkout speed stayed flat while every receipt became a signed legal document.