Integration GuideFebruary 1, 2026 · Esnad Team
How to Integrate ZATCA Phase 2 in Node.js (Complete Guide)
What ZATCA Phase 2 requires
ZATCA Phase 2 (Fatoora) requires your system to:
- Register an EGS unit — Generate ECDSA keys, build a CSR with ZATCA-specific OIDs, run a 3-invoice compliance check, and obtain a production CSID.
- Issue invoices — Build UBL 2.1 XML with the Saudi profile, maintain the Previous Invoice Hash (PIH) chain, sign with your private key, and submit to ZATCA for clearance (B2B) or report within 24h (B2C).
- Handle the QR code — Generate a TLV-encoded QR (9 tags, binary, base64, max 700 chars) for each invoice.
Building this yourself takes weeks. Using a middleware API like Esnad, you can go live in an afternoon.
Option 1: Build it yourself
You'll need to implement:
- ECDSA key generation (secp256k1) with ZATCA OIDs in the CSR
- UBL 2.1 XML generation with all Saudi namespaces and correct field ordering
- SHA-256 canonical hash and PIH chain maintenance
- TLV QR code encoding (9 tags, strict format)
- Retry logic and queue for ZATCA outages
- Certificate expiry monitoring and renewal flow
Option 2: Use Esnad API
With Esnad, you send JSON and receive a cleared invoice with UUID and QR code:
const response = await fetch('https://api.esnadapi.com/v1/invoices/simplified', {
method: 'POST',
headers: {
'Authorization': 'Bearer zatca_live_xxxxxxxxxxxx',
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
egs_unit_id: 'egs_abc123',
invoice_number: 'INV-2026-001',
invoice_date: '2026-01-15',
seller: { name: 'Your Company', vat_number: '310122393500003' },
line_items: [{ description: 'Item', quantity: 1, unit_price: 100, vat_category: 'S' }],
currency: 'SAR'
})
});
const data = await response.json();
// data.uuid, data.qr_code, data.status
Testing in sandbox
Every Esnad account gets a sandbox. Use API keys prefixed zatca_test_ to hit ZATCA's simulation endpoint. No Fatoora credentials needed to create sandbox EGS units.
Common errors
- Invalid OTP — Fatoora OTPs expire in ~5 minutes. Generate and paste quickly.
- PIH mismatch — Don't skip or reorder invoices; the hash chain must be sequential.
- QR too long — Simplified invoices have a 700-character QR limit; we handle truncation.
Skip the boilerplate. Use Esnad API. Start free — 14 days →
Skip the boilerplate. Use Esnad API.
The fastest way to integrate ZATCA compliance into any system.
Read next
Keep going — these posts connect to what you just read.