إسنادEsnad
Back to blog
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:

  1. 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.
  2. 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).
  3. 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.

← More in blog