Direct Answer / Quick Summary:

In Saudi Arabia's ZATCA Phase 2 E-Invoicing mandate, the 2D QR code printed on Simplified Tax Invoices (B2C) and embedded in Standard Tax Invoices (B2B) undergoes a fundamental security upgrade compared to Phase 1.

Phase 1 vs Phase 2 Architecture: While Phase 1 required only 5 basic text tags, Phase 2 mandates 9 cryptographic Tag-Length-Value (TLV) tags*.

The 9 Mandatory Tags: Tags 1 to 5 encode seller identity, VAT number, timestamp, total with VAT, and VAT amount. Tags 6 to 9 encode the SHA-256 Invoice XML Digest, the ECDSA Digital Signature, the Public Key, and the ZATCA Certificate Stamp Signature*.

Binary TLV Encoding:* Each tag is packed into a binary byte buffer: [Tag Number (1 byte)] + [Length of Value (1 byte)] + [Raw UTF-8 / Binary Bytes].

Final Base64 Representation: The concatenated binary TLV byte stream is converted into a Base64 string and rendered into a standard 2D barcode image measuring at least 20mm × 20mm*.

Verification: Consumers and tax inspectors scan the code using the official ZATCA (Zad) mobile app* to mathematically verify that the invoice was signed by an authorized EGS unit and has not been altered.


Phase 1 vs Phase 2 QR Codes: The Cryptographic Leap

In Phase 1 (enforced in December 2021), anyone with basic graphic design software could forge a QR code containing fake company names and VAT amounts because Phase 1 QR codes contained plain text without digital signature validation.

Under Phase 2, ZATCA introduced cryptographic binding. An authentic QR code can only be generated by software possessing a valid private key linked to an authorized ZATCA Production CSID:

Step 1Data Extraction

Extract Invoice Data

Gather seller name, 15-digit TRN, ISO 8601 timestamp, and total amounts

Step 2SHA-256 Engine

Canonicalize & Hash

Generate SHA-256 hash digest of the canonicalized UBL 2.1 invoice XML (Tag 6)

Step 3Cryptographic Signer

ECDSA Digital Signature

Sign the invoice hash with the EGS private key using secp256k1 curve (Tag 7)

Step 4Binary Packing

Pack Binary TLV Buffer

Concatenate all 9 fields using Tag-Length-Value byte serialization

Step 5Base64 Serializer

Base64 Encoding

Convert complete binary TLV buffer into a single Base64 encoded string

Step 6Physical / PDF Render

Render 2D Barcode

Render Base64 string as high-contrast QR code on thermal slips or digital PDFs


The 9 Mandatory TLV Tags: Complete Specification

The following technical matrix defines the exact byte layout, tag numbers, and data types required for Phase 2 compliance:

Tag #DescriptionTechnical Data TypeMax Length (Bytes)Source / Description
1Seller Legal NameUTF-8 StringUp to 255Sponsoring company legal name matching Commercial Registration.
2Seller 15-Digit VAT TRNASCII StringExactly 15Tax Registration Number starting with 3 and ending with 3.
3Invoice TimestampASCII (ISO 8601)Exactly 19 or 25Format: YYYY-MM-DDTHH:MM:SS (Saudi local time).
4Invoice Total (With VAT)ASCII NumericVariableTotal payable amount rounded to 2 decimal places (e.g., 1150.00).
5Total VAT AmountASCII NumericVariableTotal VAT amount rounded to 2 decimal places (e.g., 150.00).
6Invoice XML DigestBinary / HexExactly 32SHA-256 cryptographic hash of the canonicalized invoice XML.
7ECDSA Digital SignatureASN.1 / Binary~70 to 72Digital signature of the invoice digest signed by EGS private key.
8ECDSA Public KeyBinary (DER)Exactly 65 or 88Public key bytes extracted from the active EGS Production CSID.
9Certificate SignatureBinary~70 to 72Cryptographic signature of ZATCA's Trust Sub-CA that signed the CSID.

Understanding Tag-Length-Value (TLV) Binary Encoding

TLV is a binary encoding scheme where data is stored in self-describing segments:

Tag (T): A 1-byte integer identifying the field number (e.g., 0x01 for Tag 1).
Length (L): A 1-byte integer representing the total number of bytes in the value (for lengths under 128 bytes). If length exceeds 127 bytes, ASN.1 multi-byte length rules apply.
Value (V): The actual payload data bytes (UTF-8 encoded string or raw binary).

Visualizing the TLV Byte Structure

For Tag 1 containing company name "ACME":

Tag = 0x01 (1 byte)
Length = 0x04 (4 bytes)
Value = 0x41 0x43 0x4D 0x45 (ASCII representation of "ACME")
Serialized Byte Stream: 01 04 41 43 4D 45

Working Code Implementations: TLV Packing & QR Generation

Python Implementation (Reference Script)

The following Python script illustrates how to serialize the TLV buffer and produce the compliant Base64 string:

python|Technical Specification / Reference
Verified Schema
import base64
from typing import List, Tuple

def create_tlv_tag(tag_num: int, value: bytes) -> bytes:
    """Encodes a single tag, length, and value into compliant TLV bytes."""
    tag_byte = bytes([tag_num])
    length = len(value)
    
    if length < 128:
        length_bytes = bytes([length])
    else:
        # Multi-byte length encoding for large values (like public keys and signatures)
        length_bytes = bytes([0x81, length]) if length < 256 else bytes([0x82, (length >> 8) & 0xFF, length & 0xFF])
        
    return tag_byte + length_bytes + value

def generate_zatca_phase2_qr(
    seller_name: str,
    vat_number: str,
    timestamp: str,
    total_with_vat: str,
    vat_total: str,
    invoice_hash: bytes,      # 32 bytes SHA-256
    ecdsa_signature: bytes,   # Raw ASN.1 ECDSA signature
    public_key: bytes,        # Raw DER public key
    cert_signature: bytes     # ZATCA CA signature
) -> str:
    """Concatenates all 9 tags and returns Base64 encoded string."""
    tlv_buffer = bytearray()
    
    # Tags 1 to 5 (String UTF-8 values)
    tlv_buffer.extend(create_tlv_tag(1, seller_name.encode('utf-8')))
    tlv_buffer.extend(create_tlv_tag(2, vat_number.encode('ascii')))
    tlv_buffer.extend(create_tlv_tag(3, timestamp.encode('ascii')))
    tlv_buffer.extend(create_tlv_tag(4, total_with_vat.encode('ascii')))
    tlv_buffer.extend(create_tlv_tag(5, vat_total.encode('ascii')))
    
    # Tags 6 to 9 (Cryptographic binary elements)
    tlv_buffer.extend(create_tlv_tag(6, invoice_hash))
    tlv_buffer.extend(create_tlv_tag(7, ecdsa_signature))
    tlv_buffer.extend(create_tlv_tag(8, public_key))
    tlv_buffer.extend(create_tlv_tag(9, cert_signature))
    
    # Final Base64 encoding
    return base64.b64encode(tlv_buffer).decode('ascii')

Physical Printing & Scanning Requirements

Generating the Base64 string is only half the equation; the physical barcode must be readable by consumer smartphones in retail settings:

Statutory Safeguards & Rights Protection

Mandatory protections enforced by MHRSD & Saudi Labor Law

1
Physical Dimension StandardThe printed QR code must measure at least 20mm x 20mm (approximately 0.79 inches) on paper thermal receipts.
2
High Contrast PrintingMust be printed with black modules on a pure white background. Light gray, thermal fading, or colored printing is prohibited.
3
Quiet Zone MarginMust maintain a minimum 4-module quiet zone (white space border) around the barcode perimeter to ensure optical autofocus recognition.
4
Error Correction LevelRecommended error correction is Level L (7%) or Level M (15%) to prevent dense module clutter on high-payload Phase 2 QR codes.

Testing & Verification with the Official ZATCA Mobile App

Taxpayers and developers can verify their QR codes using the official government inspection tool:

1Download the ZATCA (Zad / زاد) application from Google Play or the Apple App Store.
2Select the Scan QR Code (مسح الرمز) scanner tool.
3Aim the camera at your generated thermal receipt or PDF screen.
4Valid Output: The app displays a green verification shield confirming:

- Taxpayer Name & Valid VAT Number

- Exact Transaction Timestamp

- Invoice Financial Breakdown

- Verified Cryptographic Signature Match

5Invalid / Warning Output: If the app displays a red warning or fails to parse, inspect your TLV length headers and ensure Tag 6 hash matches the XML digest.

Frequently Asked Questions (FAQ)

Can I include custom business text or URLs inside the ZATCA QR code?

No. Adding extra non-standard tags, website links, or promotional text inside the ZATCA QR code byte buffer violates Schematron business rules. The QR code must contain exclusively the authorized TLV tags mandated by ZATCA specifications.

Why is the Phase 2 QR code significantly denser than Phase 1?

Phase 1 QR codes contained approximately 80 to 120 bytes of plain text. Phase 2 QR codes incorporate cryptographic signatures, hashes, and public keys, resulting in a payload of 500 to 700 bytes. This increased payload produces a visibly denser 2D matrix.

Is the QR code mandatory on B2B Standard Tax Invoices?

Under Phase 2 rules, the QR code is mandatory inside the UBL 2.1 XML document for both B2B and B2C invoices. On printed or visual PDF representations, the QR code is mandatory on Simplified (B2C) invoices, but optional on human-readable Standard (B2B) invoices.

What happens if the thermal printer cuts off part of the QR code?

If a thermal printer clips the QR code or prints with low contrast, the invoice is treated as a defective receipt under VAT regulations. Sponsoring establishments are subject to statutory fines starting at SAR 1,000 for issuing illegible electronic receipts.

Does the QR code timestamp need to include timezone offsets?

No. The timestamp format must follow YYYY-MM-DDTHH:MM:SS in local Saudi Arabia standard time (GMT+3) without trailing timezone characters like Z or +03:00.