In the Saudi Arabian business landscape, the QR code on an e-invoice is far more than a simple URL shortcut. It is a strictly encoded, cryptographic data structure mandated by the Zakat, Tax and Customs Authority (ZATCA). Whether you are in Phase 1 (Generation) or Phase 2 (Integration), ensuring your QR code complies with the TLV (Tag-Length-Value) encoding standard is critical to avoiding fines and invoice rejections.
This guide provides a comprehensive breakdown of the technical requirements, the underlying TLV binary structure, and a complete TypeScript/Node.js implementation.
1. What is TLV Encoding?
ZATCA requires QR code data to be formatted using the TLV (Tag-Length-Value) method before being converted into a Base64 string. This ensures that the data is compact, deterministic, and easily readable by the Fatoora simulation and production environments.
The Anatomy of TLV
- Tag: A 1-byte identifier for the data field (e.g., Tag 1 for Seller Name).
- Length: The length (in bytes) of the value field.
- Value: The raw UTF-8 byte representation of the data.
Required Fields for Phase 1 (Simplified & Standard Invoices)
For Phase 1, the QR code must contain the following five tags:
| Tag | Field Name | Description | Example |
|---|---|---|---|
| 1 | Seller Name | Legal entity name as registered with ZATCA | Qeemah Software |
| 2 | VAT Number | 15-digit VAT registration number | 300000000000003 |
| 3 | Timestamp | Invoice issuance timestamp (ISO 8601 UTC/Z) | 2026-10-23T06:00:00Z |
| 4 | Invoice Total | Total invoice amount including VAT | 1150.00 |
| 5 | VAT Total | Total VAT amount charged | 150.00 |
2. Phase 2: Cryptographic Extensions
In Phase 2 (Integration Phase), the QR code for Simplified Tax Invoices (B2C) becomes a cryptographic proof of document integrity.
In addition to Tags 1 through 5, Phase 2 mandates four additional cryptographic tags:
- Tag 6 (Invoice Hash): The SHA-256 hash of the sanitized invoice XML.
- Tag 7 (Digital Signature): An ECDSA digital signature (secp256k1) generated using the private key associated with your Cryptographic Stamp (CSID).
- Tag 8 (Public Key): The ECDSA public key used by ZATCA to verify the signature.
- Tag 9 (Certificate Signature): For simplified invoices, the digital signature of the CSID certificate itself.
3. Step-by-Step Implementation in Node.js / TypeScript
Here is a clean, production-ready utility to generate compliant ZATCA TLV Base64 QR strings:
import { Buffer } from "node:buffer"; interface ZATCAQRData { sellerName: string; vatNumber: string; timestamp: string; invoiceTotal: string; vatTotal: string; invoiceHash?: string; signature?: string; publicKey?: string; certificateSignature?: string; } function encodeTLVField(tag: number, value: string | Buffer): Buffer { const valBuf = Buffer.isBuffer(value) ? value : Buffer.from(value, "utf8"); const tagBuf = Buffer.from([tag]); const lenBuf = Buffer.from([valBuf.length]); return Buffer.concat([tagBuf, lenBuf, valBuf]); } export function generateZATCAQRCode(data: ZATCAQRData): string { const buffers: Buffer[] = [ encodeTLVField(1, data.sellerName), encodeTLVField(2, data.vatNumber), encodeTLVField(3, data.timestamp), encodeTLVField(4, data.invoiceTotal), encodeTLVField(5, data.vatTotal), ]; if (data.invoiceHash) { buffers.push(encodeTLVField(6, data.invoiceHash)); } if (data.signature) { buffers.push(encodeTLVField(7, data.signature)); } if (data.publicKey) { buffers.push(encodeTLVField(8, data.publicKey)); } if (data.certificateSignature) { buffers.push(encodeTLVField(9, data.certificateSignature)); } const combined = Buffer.concat(buffers); return combined.toString("base64"); } 4. Common Validation Pitfalls
When submitting to the Fatoora portal, common rejection errors include:
-
BR-KSA-26/BR-KSA-27: The QR code does not conform to the TLV structure or is missing mandatory tags. - Timestamp Mismatch: The timestamp in Tag 3 must match the
cbc:IssueDateandcbc:IssueTimeXML elements exactly to the second. - Character Encoding: Seller names with Arabic characters must be encoded strictly in UTF-8 to ensure byte-length calculations match the TLV length header.
Conclusion & Resources
Building compliant e-invoicing pipelines requires strict adherence to cryptographic standards and binary data structures.
If you are developing or managing business infrastructure in Saudi Arabia, Qeemah provides a modern, fully compliant cloud ERP and accounting platform with native ZATCA Phase 2 clearance and automated cryptographic stamping.
Original article published on Qeemah Cloud Accounting.

![Why Object.keys(user) Returns string[], Not (keyof User)[]: TypeScript Means It](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2q4w48b9bzs43tynyhsf.png)