Skip to content

ZATCA Package

Section: 16 — Packages
Last Updated: 2026-05-30
Scope: Microtec.Zatca — Saudi E-Invoicing Phase 1 and Phase 2


Overview

The Microtec.Zatca package implements Saudi Arabia's Zakat, Tax and Customs Authority (ZATCA) e-invoicing mandate. It handles both phases of compliance:

PhaseRequirementWhat the package does
Phase 1QR code on every invoiceTLV-encoded QR generation
Phase 2Cryptographic signing + ZATCA clearance/reportingCSID onboarding, UBL 2.1 XML, clearance API

Source Location

Platforms/Src/InfrastructureServices/Zatca/ — the package is also consumed by the Integration service as an external NuGet dependency.


Package Structure

Microtec.Zatca.Infrastructure   ← Core implementation
Microtec.Zatca.Integration      ← Integration events and public API client

Microtec.Zatca.Infrastructure

CategoryWhat's Included
Main serviceIZatcaService, ZatcaService
Phase 1QrCodeGenerator — TLV encoding per ZATCA spec
Phase 2ZatcaXmlBuilder — UBL 2.1 XML invoice
Phase 2ZatcaSigningService — X.509 certificate + digital signature
OnboardingZatcaComplianceClient — CSID onboarding API
ClearanceZatcaClearanceClient — invoice clearance API
ReportingZatcaReportingClient — simplified invoice reporting API
ModelsZatcaInvoice, ZatcaLineItem, ZatcaConfig, ClearanceResult

Microtec.Zatca.Integration

What's Included
InvoiceSubmittedToZatcaEvent — raised after invoice is submitted
ZatcaClearedEvent — raised when ZATCA clears the invoice
ZatcaRejectedEvent — raised when ZATCA rejects with validation errors
IZatcaPublicApi — typed HTTP client for cross-service calls

Phase 1 — QR Code Generation

Phase 1 requires a TLV-encoded QR code printed on every invoice. The QR encodes seller name, VAT number, timestamp, invoice total, and VAT amount.

Configuration

json
// appsettings.json
{
  "Zatca": {
    "Phase": 1,
    "SellerName": "Microtec Technology",
    "VatRegistrationNumber": "310XXXXXXXXX0003",
    "Environment": "Production"
  }
}

Usage

csharp
// Program.cs
builder.Services.AddZatcaPhase1(builder.Configuration);

// In a command handler
public class AddInvoiceCommandHandler(IZatcaService zatca, IClockService clock)
{
    public async Task<int> Handle(AddInvoiceCommand request, CancellationToken ct)
    {
        var qrCode = zatca.GenerateQrCode(new ZatcaInvoice
        {
            SellerName     = "Microtec Technology",
            VatNumber      = "310XXXXXXXXX0003",
            Timestamp      = clock.Now,
            InvoiceTotal   = request.Total,
            VatAmount      = request.VatAmount
        });

        // qrCode is a Base64 string — embed directly in the PDF
        var invoice = Invoice.Create(request, qrCode);
        // ...
    }
}

TLV Field Reference

TagFieldMax Length
1Seller name255
2VAT registration number15
3Invoice timestamp (ISO 8601)20
4Invoice total (with VAT)20
5VAT amount20

Phase 2 — CSID Onboarding and Invoice Clearance

Phase 2 adds cryptographic signing and real-time clearance. Every standard tax invoice (B2B, above threshold) must be cleared by ZATCA before it is legally valid. Simplified invoices (B2C) go through the reporting API.

Prerequisites

Phase 2 requires:

  1. A CSID (Cryptographic Stamp Identifier) — issued by ZATCA during onboarding
  2. A private key + X.509 certificate — generated during CSR submission
  3. Access to ZATCA's compliance or production API

Onboarding is a one-time process per device/environment

The CSID and certificate pair are bound to the onboarding environment. Production CSIDs cannot be used against the sandbox API and vice versa. Each Azure environment (stage, preprod, production) needs its own onboarding.

Configuration

json
// appsettings.json (values in Key Vault in live environments)
{
  "Zatca": {
    "Phase": 2,
    "SellerName": "Microtec Technology",
    "VatRegistrationNumber": "310XXXXXXXXX0003",
    "Environment": "Sandbox",
    "Csid": "keyvaultref:zatca--csid",
    "PrivateKey": "keyvaultref:zatca--private-key",
    "Certificate": "keyvaultref:zatca--certificate",
    "ApiBaseUrl": "https://gw-fatoora.zatca.gov.sa/e-invoicing/developer-portal"
  }
}
Environment valueAPI endpoint
Sandboxhttps://gw-fatoora.zatca.gov.sa/e-invoicing/developer-portal
Simulationhttps://gw-fatoora.zatca.gov.sa/e-invoicing/simulation
Productionhttps://gw-fatoora.zatca.gov.sa/e-invoicing/core

Service Registration

csharp
// Program.cs
builder.Services.AddZatcaPhase2(builder.Configuration);

CSID Onboarding Flow

csharp
// Run once per environment during setup (not per invoice)
public class ZatcaOnboardingService(IZatcaService zatca)
{
    public async Task OnboardAsync()
    {
        // 1. Generate CSR
        var (privateKey, csr) = zatca.GenerateCsr(new CsrRequest
        {
            CommonName   = "Microtec Technology",
            SerialNumber = "1-Microtec|2-Integration|3-001",
            VatNumber    = "310XXXXXXXXX0003",
            CountryCode  = "SA",
            InvoiceType  = "1100"   // Standard + Simplified
        });

        // 2. Submit CSR to compliance API → receive CSID
        var onboardResult = await zatca.OnboardAsync(csr);

        // 3. Store CSID, privateKey, and certificate in Key Vault
        // These are then read back via appsettings keyvaultref entries
        Console.WriteLine($"CSID: {onboardResult.BinarySecurityToken}");
        Console.WriteLine($"Secret: {onboardResult.Secret}");
    }
}

Standard Invoice Clearance (B2B)

csharp
public class ClearInvoiceCommandHandler(IZatcaService zatca)
{
    public async Task Handle(ClearInvoiceCommand request, CancellationToken ct)
    {
        var zatcaInvoice = BuildZatcaInvoice(request);

        // Signs and submits the invoice for clearance
        var result = await zatca.ClearInvoiceAsync(zatcaInvoice, ct);

        if (result.IsCleared)
        {
            // result.ClearedXml contains the ZATCA-stamped XML
            // Store result.InvoiceHash for later reference
        }
        else
        {
            throw new DomainException($"ZATCA rejected invoice: {result.ValidationResults}");
        }
    }
}

Simplified Invoice Reporting (B2C)

csharp
var result = await zatca.ReportInvoiceAsync(zatcaInvoice, ct);
// No clearance required — ZATCA acknowledges asynchronously

Sandbox vs Production

ConcernSandboxProduction
CSID validityTest CSID from ZATCA portalIssued via compliance onboarding
Invoice numbersAny formatMust be sequential, no gaps
Rejection consequenceNo legal impactInvoice is invalid until cleared
API rate limitsRelaxedEnforced (429 on burst)
Data retentionZATCA may purgePermanent

Never mix environments

A production CSID submitted to the sandbox API returns 400 Bad Request. A sandbox CSID on the production API is rejected. Always confirm Zatca:Environment in appsettings matches the CSID origin environment before deploying.


Key Vault Secret Names

Secret Key Vault NameMaps to Config KeyDescription
Zatca--CsidZatca:CsidBinary security token from onboarding
Zatca--PrivateKeyZatca:PrivateKeyPEM-encoded EC private key
Zatca--CertificateZatca:CertificateBase64-encoded X.509 certificate

Key Vault naming convention

Azure Key Vault does not allow __ (double underscore) in secret names. Use -- (double dash) instead. The Microtec.Web.Hosting bootstrap automatically translates -- back to : when reading configuration.


Integration Events

Other services subscribe to ZATCA events via the Service Bus:

csharp
// Subscribe in your consumer registration
busConfig.AddConsumer<ZatcaClearedEventHandler>();
busConfig.AddConsumer<ZatcaRejectedEventHandler>();

// Handler example
public class ZatcaClearedEventHandler : ConsumerBase<ZatcaClearedEvent>
{
    public override async Task Consume(ConsumeContext<ZatcaClearedEvent> context)
    {
        var ev = context.Message;
        // ev.InvoiceId, ev.ClearedAt, ev.InvoiceHash
        await _invoiceRepository.MarkClearedAsync(ev.InvoiceId, ev.ClearedAt);
    }
}

Troubleshooting

SymptomLikely CauseFix
400 — Faulty invoice formatUBL XML does not match schemaCheck invoice type code and mandatory fields
401 — Invalid CSIDWrong environment or expired CSIDRe-onboard; verify Zatca:Environment
429 — Too many requestsBurst limit hitImplement exponential backoff; use the reporting API for B2C
QR code not scanningTLV encoding errorValidate with ZATCA's Fatoora mobile app
Certificate chain validation failedProduction certificate not trustedEnsure ZATCA root CA is included in the trust store

Internal Documentation — Microtec Platform Team