Country & TaxFree generatorPDF, Excel, Word exportSaudi Arabia

ZATCA Simplified Invoice QR TLV Base64 Python Generator

Saudi invoices carry a QR code whose payload is a Base64 string of tag-length-value fields. This generator writes the Python that builds that string from your seller and invoice data, so you can test it or adapt it in a print or middleware step.

Fill in

15 digits, starting and ending with 3 for Saudi VAT numbers.

Generated code
Download:

Python script

import base64

def tlv(tag, value):
    data = value.encode("utf-8")
    if len(data) > 255:
        raise ValueError("field too long for single byte length")
    return bytes([tag, len(data)]) + data

payload = b"".join([
    tlv(1, "Al Noor Industrial Co"),
    tlv(2, "300000000000003"),
    tlv(3, "2026-10-20T10:30:00Z"),
    tlv(4, "1150.00"),
    tlv(5, "150.00"),
])

qr_text = base64.b64encode(payload).decode("ascii")
print(qr_text)

Tag map used above

Tag 1: seller name
Tag 2: seller VAT registration number
Tag 3: invoice date and time
Tag 4: invoice total including VAT
Tag 5: VAT amount

Each field is encoded as one byte tag, one byte length, then the UTF-8 value. The joined bytes are Base64 encoded and that string is what the QR image contains.

This covers the basic five tag structure used for the Saudi QR code. Phase 2 invoices add further tags (such as invoice hash, signature and public key) produced by the cryptographic stamp, which this script does not create. Check the current ZATCA technical specification and your solution provider's requirements before relying on it for live invoices.

Plan a ZATCA integration around your ERP

Optional: a short walk-through of how invoice data can flow from your ERP to the e-invoicing layer.

Optional. The tool and every export work without this. No spam.

How to use the generator

Fill in the seller name, VAT number, the invoice timestamp, the total including VAT and the VAT amount. Copy the script and run it with any Python 3 interpreter. It prints the Base64 text. Feed that text to a QR library or to your report writer's QR barcode element, rather than printing it as visible text. Because the length byte is a single byte, each field must stay under 256 bytes, which matters for long Arabic seller names since Arabic characters take two bytes each in UTF-8.

  • Use a full ISO 8601 timestamp with a time component.
  • Format amounts with two decimals as they appear on the invoice.
  • Test the result by scanning it with a QR reader that decodes Base64.

The TLV method

TLV stands for tag, length, value. Each of the basic fields is written as one byte for the tag number, one byte for the number of value bytes, then the value itself in UTF-8. All the fields are concatenated in tag order and the whole byte sequence is Base64 encoded. A reader reverses the steps. If the encoded length does not equal the value byte count, the reader will mis-parse every later field, so counting bytes rather than characters is the point most implementations get wrong.

Where this fits and what it does not do

The simplified tax invoice used for business to consumer sales carries this QR code. Under the Fatoora integration phase the invoice is also generated as structured XML, cryptographically stamped and reported or cleared through ZATCA, and that stamped invoice carries additional QR tags. This script is useful for understanding the format, for testing a print layout and for prototyping, but a compliant production flow needs the full solution described in ZATCA's technical documents. Plan for the integration with your ERP's invoice posting and for storing the generated XML.

  • Confirm which fields your ERP localisation already produces.
  • Do not hard code test VAT numbers into production jobs.
  • Retain the QR payload with the invoice record for audit.

Frequently Asked Questions

What is TLV in the ZATCA QR code?

TLV means tag, length, value. Each field is stored as a one byte tag, a one byte length and the value bytes. The fields are joined and the whole result is Base64 encoded to form the QR text.

Why is my QR code failing validation?

The usual causes are counting characters instead of UTF-8 bytes for the length, a wrong timestamp format, amounts that do not match the printed invoice, or fields in the wrong order. Decode your Base64 and read each tag in turn to find the mismatch.

Does this replace a ZATCA compliant solution?

No. It only builds the basic QR payload. A compliant solution also produces the structured invoice, applies the cryptographic stamp and handles reporting or clearing with ZATCA as required for your invoice type.

Do Arabic seller names work?

Yes, if encoded as UTF-8 and the length byte uses the byte count. Arabic letters use two bytes each, so a name of 130 characters would exceed the 255 byte limit and must be shortened to the registered form.

If you need ZATCA invoice data pulled out of your ERP into a clean, testable middleware layer, we can scope that with your finance and IT teams.