PHPackages                             aghfatehi/laravel-zatca - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. aghfatehi/laravel-zatca

ActiveLibrary[Payment Processing](/categories/payments)

aghfatehi/laravel-zatca
=======================

Laravel ZATCA (Fatoora) package for Saudi e-invoicing Phase 1 &amp; Phase 2 compliance. دمج الفاتورة الإلكترونية السعودية مع لارافيل - المرحلة الأولى والثانية لهيئة الزكاة والضريبة والجمارك

v1.4.0(1mo ago)114↓90%MITPHPPHP ^8.1|^8.2|^8.3|^8.4CI passing

Since Jun 3Pushed 1mo agoCompare

[ Source](https://github.com/aghfatehi/laravel-zatca)[ Packagist](https://packagist.org/packages/aghfatehi/laravel-zatca)[ RSS](/packages/aghfatehi-laravel-zatca/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (5)Dependencies (8)Versions (6)Used By (0)

 [![PHP Version](https://camo.githubusercontent.com/d4fe5599dc4fb02fe432b94f8a25d1b06cfc6fbaad6f0baa6dc87ee043ca3e98/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d5e382e312d3838393242462e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d706870)](https://www.php.net/) [![Laravel Version](https://camo.githubusercontent.com/b7659162668560f1d9c9b9f097fe5f0f26b317a9b789c2908148eadc43f15cf5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d397c31307c31317c31327c31332d4646324432302e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d6c61726176656c)](https://laravel.com/) [![ZATCA Phase 1 & 2](https://camo.githubusercontent.com/6735be3e8193777dafd57bf453c87b3ffeb5b6e57c7ec1e4cf24a3301a7acafc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5a415443412d50686173655f315f2532425f50686173655f322d3030413835392e7376673f7374796c653d666f722d7468652d6261646765)](https://zatca.gov.sa/) [![License](https://camo.githubusercontent.com/31e62e0eff03ce9ddfdf69d8476340d4f541990bfb152cb02a0f342965252997/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e7376673f7374796c653d666f722d7468652d6261646765)](LICENSE) [![Tests](https://camo.githubusercontent.com/79767217e52ac491d816d4167a725ace541e0d27855e8b0fcccfadfb9c3e57cb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6167686661746568692f6c61726176656c2d7a617463612f6c61726176656c2e796d6c3f7374796c653d666f722d7468652d6261646765266c6162656c3d5465737473)](https://github.com/aghfatehi/laravel-zatca/actions) [![Packagist](https://camo.githubusercontent.com/3302ddcf4e4cd4286dcb70c951f58711c84e93e5edc4696ceeb1015d9b3f280c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6167686661746568692f6c61726176656c2d7a617463612e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/aghfatehi/laravel-zatca) [![Downloads](https://camo.githubusercontent.com/a95f998167241a0a1d14f6e0b6925a8ef5865427dfabc3d4d8274a4c033efafd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6167686661746568692f6c61726176656c2d7a617463612e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/aghfatehi/laravel-zatca) [![Author](https://camo.githubusercontent.com/369b3da733224d2abc71724d11cef62b04f53ad2dcd876721f32e0d989da39d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f417574686f722d414c2d2d414748424152492532304661746568692d626c75652e7376673f7374796c653d666f722d7468652d6261646765)](https://github.com/aghfatehi)

Laravel ZATCA (Fatoora) Package
===============================

[](#laravel-zatca-fatoora-package)

### Saudi Arabian e-Invoicing Compliance — Phase 1 &amp; Phase 2

[](#saudi-arabian-e-invoicing-compliance--phase-1--phase-2)

### المرحلة الأولى والثانية للفاتورة الإلكترونية السعودية لهيئة الزكاة والضريبة والجمارك

[](#المرحلة-الأولى-والثانية-للفاتورة-الإلكترونية-السعودية-لهيئة-الزكاة-والضريبة-والجمارك)

#### By [AL-AGHBARI Fatehi](https://github.com/aghfatehi) — **فتحي الأغبري**

[](#by-al-aghbari-fatehi--فتحي-الأغبري)

 **ZATCA integration for Laravel — QR code generation, TLV encoding, invoice signing, clearance &amp; reporting. دمج الفاتورة الإلكترونية مع لارافيل: المرحلة الأولى (QR) والمرحلة الثانية (التوقيع والإرسال) لهيئة الزكاة والضريبة والجمارك السعودية**

---

Table of Contents
-----------------

[](#table-of-contents)

- [Overview](#overview)
- [Features](#features)
- [Version Matrix](#version-matrix)
- [Installation](#installation)
- [Configuration](#configuration)
- [Integration Scenarios](#integration-scenarios)
- [Phase 1 -- QR Code Generation](#phase-1--qr-code-generation-basic-compliance)
- [Phase 2 -- FATOORA API Integration](#phase-2--fatoora-api-integration-full-compliance)
- [QR Code Display on PDF / View](#qr-code-display-on-pdf--view)
- [API Routes](#api-routes)
- [Offline Mode &amp; Queue Sync](#offline-mode--queue-sync)
- [Events](#events)
- [Artisan Commands](#artisan-commands)
- [Testing](#testing)
- [Security &amp; Logging](#security--logging)
- [Project Map](./PROJECT_MAP.md)
- [Support](#support)

---

Overview
--------

[](#overview)

**laravel-zatca** is a production-grade Laravel package for integrating with the **ZATCA (Zakat, Tax and Customs Authority)** e-invoicing system — also known as **Fatoora** — in the Kingdom of Saudi Arabia.

The package covers both phases of the ZATCA e-invoicing mandate:

PhaseDescriptionStatus**Phase 1**Generate and display QR code on invoices (TLV Base64 format)Production Ready**Phase 2**Full compliance: CSR, Certificate, Signing, Clearance &amp; Reporting via FATOORA APIProduction Ready### Flexible Integration

[](#flexible-integration)

You can use this package in any of these modes:

1. **Phase 1 only** — Just generate QR codes for display on PDF/View (no API calls)
2. **Phase 2 only** — Full API integration (requires pre-existing Phase 1 QR or external QR generation)
3. **Both phases** — Full lifecycle from QR → Signing → Submission
4. **Offline → Online** — Generate QR codes offline, sync invoices via queue when online

### What is Required vs Optional

[](#what-is-required-vs-optional)

**For Phase 1 (QR generation only):**

StepRequired?Install package (`composer require`)**Required**Set `ZATCA_PHASE` and `ZATCA_VAT_*` in `.env`**Required**Call `Zatca::phase1()->generateQrCodeText()` in your controller**Required**Display QR in your Blade view**Required**Publish config / viewsOptionalInstall `simplesoftwareio/simple-qrcode` or `endroid/qr-code` for ZATCA-compatible QROptional but **recommended**Use Model Trait for automatic QR generationOptionalAPI Routes (`/zatca/onboard`, etc.)Optional — not neededOffline Mode &amp; Queue SyncOptional — not neededEvents &amp; LoggingOptional — not needed**For Phase 2 (API integration):**

StepRequired?Everything from Phase 1**Required** (if using `both`)Set `ZATCA_PHASE=phase_2` or `=both`**Required**Complete onboarding (keys + CSR + certificate)**Required**Set `ZATCA_CERTIFICATE`, `ZATCA_PRIVATE_KEY`, `ZATCA_SECRET`**Required**Call `Zatca::phase2()->signInvoice()` + `->submitInvoice()`**Required**Publish migrations for audit loggingOptionalUse Queue for async syncOptionalAPI Routes (`/zatca/onboard`)Optional — alternative to CLIEvents &amp; custom listenersOptional---

Features
--------

[](#features)

- **Phase 1**: TLV Base64 QR code (5 tags: Seller, VAT, Date, Total, Tax)
- **Phase 2**: UBL 2.1 XML invoice building &amp; XAdES signing
- **Phase 2**: ECDSA secp256k1 key pair generation (OpenSSL)
- **Phase 2**: CSR generation for ZATCA compliance certificate
- **Phase 2**: Compliance check (Sandbox)
- **Phase 2**: Clearance &amp; Reporting (Production)
- **cURL-based** HTTP client (no Guzzle dependency)
- **Queue support** for async invoice sync with retry logic
- **Offline mode** -- Generate signed XML locally, sync later
- **Artisan commands** for onboarding &amp; syncing
- **Event-driven** architecture (InvoiceCleared, InvoiceReported, InvoiceFailed)
- **PSR-4 autoloading**, Service Provider auto-discovery
- **Logging** with PII masking, non-blocking design
- **No UI/frontend assumptions** -- Bring your own views
- **Configurable phases** via single `.env` variable

---

External References
-------------------

[](#external-references)

This package implements technical specifications for e-invoicing. Below are links to the relevant standards and portals for your own compliance verification.

ResourceLinkZATCA Developer Portal (Sandbox)ZATCA Production PortalE-invoicing regulations (Saudi Arabia)> This package is built by implementing publicly available technical specifications. For official compliance requirements, always refer to ZATCA's documentation and consult with legal advisors.

---

Version Matrix
--------------

[](#version-matrix)

ComponentVersion**PHP**`^8.1`, `^8.2`, `^8.3`, `^8.4`**Laravel**`^9.0`, `^10.0`, `^11.0`, `^12.0`, `^13.0`**ZATCA API**V2 (2024+)**UBL Standard**2.1**Signature Algorithm**ECDSA secp256k1 + SHA-256**XAdES**EPES v1.3.2**QR Encoding**TLV Base64 (GS1-compatible)**OpenSSL**Required (for key &amp; CSR generation)**cURL**Required extension### Optional QR Dependencies

[](#optional-qr-dependencies)

The built-in QR generator (`SvgQrGenerator`) produces **visual-only output** that is **not** compatible with the official ZATCA (Fatoora) app. For production use, you **must** install one of these:

PackagePurposeInstall`simplesoftwareio/simple-qrcode`✅ ZATCA-compatible SVG QR`composer require simplesoftwareio/simple-qrcode``endroid/qr-code`✅ ZATCA-compatible QR (SVG/PNG)`composer require endroid/qr-code`If one of these is installed, the **Blade view** uses it automatically. If neither is installed, the built-in fallback produces a QR image that will **not** be readable by the ZATCA app.

---

Installation
------------

[](#installation)

```
composer require aghfatehi/laravel-zatca
```

**That's it for Phase 1** — TLV generation works immediately. For QR rendering, you must install `simplesoftwareio/simple-qrcode` or `endroid/qr-code` (see [Optional QR Dependencies](#optional-qr-dependencies)). For Phase 2 you also need OpenSSL installed on your server and a ZATCA developer account.

### Publish Configuration

[](#publish-configuration)

```
php artisan vendor:publish --tag=zatca-config
```

### Publish Migrations (Optional — for Phase 2 API &amp; audit logging)

[](#publish-migrations-optional--for-phase-2-api--audit-logging)

Publish and run the migrations only if you are using the optional Phase 2 API routes (onboarding, invoice clearance/reporting):

```
php artisan vendor:publish --tag=zatca-migrations
php artisan migrate --path=/database/migrations/2024_01_01_000001_create_zatca_certificates_table.php
php artisan migrate --path=/database/migrations/2024_01_01_000002_create_zatca_invoice_logs_table.php
```

This creates two tables:

TablePurpose`zatca_certificates`Stores EGS certificate and private key after ZATCA onboarding (used for invoice signing)`zatca_invoice_logs`Logs every invoice submission request/response with `invoice_serial_number` for clearance &amp; reporting audit trailYou do **not** need these migrations if you only use Phase 1 (QR code generation).

### Publish Views (Optional — to customize QR fallback)

[](#publish-views-optional--to-customize-qr-fallback)

```
php artisan vendor:publish --tag=zatca-views
```

Copies `qr-code.blade.php` to `resources/views/vendor/zatca/` so you can customize the default SVG layout.

> **Note:** This view auto-detects `simplesoftwareio/simple-qrcode`, `endroid/qr-code`, and falls back to the built-in generator. Publish only if you need to customize the template.

### Verify Installation

[](#verify-installation)

```
php artisan zatca:check
```

---

Configuration
-------------

[](#configuration)

Set these in your `.env` file:

```
# --- Phase Selection ---
ZATCA_PHASE=both                   # phase_1, phase_2, both

# --- Environment ---
ZATCA_ENVIRONMENT=sandbox          # sandbox | production
```

### Env Variables Reference

[](#env-variables-reference)

VariableRequiredDescriptionWhere to get it`ZATCA_PHASE`YesWhich phase to enable: `phase_1`, `phase_2`, or `both`You choose`ZATCA_ENVIRONMENT`Yes`sandbox` for testing, `production` for liveYou choose`ZATCA_EGS_UUID`Phase 2Unique ID for your ERP/Government SystemGenerated by you (any UUID v4). Used to identify your system to ZATCA.`ZATCA_VAT_NUMBER`YesYour company VAT number (15 digits in Saudi Arabia)Your company tax registration`ZATCA_VAT_NAME`YesYour company legal name as registered with ZATCAYour company registration`ZATCA_CRN_NUMBER`Phase 2Commercial Registration NumberYour company commercial registry`ZATCA_INDUSTRY`Phase 2Business industry (e.g., Retail, Healthcare)Your company profile`ZATCA_CITY`Phase 2City name (e.g., Riyadh, Jeddah)Your business address`ZATCA_CITY_SUBDIVISION`Phase 2City district or suburbYour business address`ZATCA_STREET`Phase 2Street nameYour business address`ZATCA_BUILDING`Phase 2Building numberYour business address`ZATCA_PLOT_ID`Phase 2Plot identification numberYour business address`ZATCA_POSTAL_ZONE`Phase 2Postal/ZIP codeYour business address`ZATCA_BRANCH_NAME`Phase 2Branch name (e.g., Main Branch)Your business structure`ZATCA_QUEUE_CONNECTION`OptionalQueue driver for async sync (`sync`, `redis`, `database`)Your Laravel queue config`ZATCA_QUEUE_NAME`OptionalQueue name for ZATCA jobsYou choose`ZATCA_QUEUE_TRIES`OptionalMax retry attempts on failureYou choose`ZATCA_QUEUE_TIMEOUT`OptionalJob timeout in secondsYou choose`ZATCA_RETRY_DELAY_MINUTES`OptionalDelay between retries in minutesYou choose`ZATCA_API_MIDDLEWARE`OptionalMiddleware group for API routes (default: `api`)You choose`ZATCA_CERTIFICATE`Phase 2Base64-encoded compliance certificate from ZATCA**ZATCA Developer Portal** → after running `zatca:onboard` with OTP. The certificate is the `binarySecurityToken` returned by the compliance API.`ZATCA_PRIVATE_KEY`Phase 2Base64-encoded EC private key (secp256k1)**Generated by you** via `zatca:onboard` or `Zatca::phase2()->generateKeysAndCsr()`. Store securely — this is your secret key for signing invoices.`ZATCA_SECRET`Phase 2Secret string returned by ZATCA during onboarding**ZATCA Developer Portal** → returned alongside the certificate when you issue a compliance certificate with OTP.### How the onboarding flow works

[](#how-the-onboarding-flow-works)

```
1. You run:  php artisan zatca:onboard --otp=123456 --save
2. Package generates EC key pair (private_key + public_key)
3. Package creates a CSR (Certificate Signing Request)
4. Package sends CSR + OTP to ZATCA API
5. ZATCA returns:
   - binarySecurityToken → save as ZATCA_CERTIFICATE
   - secret              → save as ZATCA_SECRET
6. Your private_key      → save as ZATCA_PRIVATE_KEY

```

The OTP is obtained from the [ZATCA Developer Portal](https://sandbox.zatca.gov.sa) (sandbox) or ZATCA production portal.

### Full config reference

[](#full-config-reference)

See [`config/zatca.php`](config/zatca.php) for all available options with documentation.

---

Phase 1 -- QR Code Generation (Basic Compliance)
------------------------------------------------

[](#phase-1----qr-code-generation-basic-compliance)

Phase 1 requires **no API calls**. It generates a TLV-encoded Base64 QR string containing:

TagFieldExample1Seller Name`شركة التقنية`2VAT Number`300000000000003`3Date/Time (ISO 8601)`2024-01-01T12:00:00Z`4Invoice Total (SAR)`115.00`5VAT Total (SAR)`15.00`### Usage

[](#usage)

```
use Aghfatehi\Zatca\Facades\Zatca;

// Simple QR text generation
$qrText = Zatca::phase1()->generateQrCodeText(
    sellerName: 'شركة التقنية',
    vatNumber: '300000000000003',
    invoiceDate: '2024-01-01T12:00:00Z',
    totalAmount: '115.00',
    taxAmount: '15.00',
);

// Base64-encoded TLV string ready for embedding
echo $qrText;
```

### Using with Invoice DTO

[](#using-with-invoice-dto)

```
use Aghfatehi\Zatca\DTO\InvoiceDTO;

$invoice = InvoiceDTO::fromArray([
    'invoice_serial_number' => 'INV-001',
    'issue_date' => '2024-01-01',
    'issue_time' => '12:00:00',
    'line_items' => [
        [
            'id' => '1',
            'name' => 'Product A',
            'quantity' => 2,
            'tax_exclusive_price' => 100.00,
            'vat_percent' => 0.15,
        ],
    ],
]);

$egsUnit = [
    'vat_name' => 'شركة التقنية',
    'vat_number' => '300000000000003',
];

$qrText = Zatca::phase1()->generateQrCodeFromInvoice($invoice, $egsUnit);
```

---

Phase 2 -- FATOORA API Integration (Full Compliance)
----------------------------------------------------

[](#phase-2----fatoora-api-integration-full-compliance)

Phase 2 requires completing the ZATCA onboarding process to obtain a compliance certificate, then signing and submitting invoices.

### Step 1: Onboarding (One-time setup)

[](#step-1-onboarding-one-time-setup)

Generate EC key pair, CSR, and get compliance certificate from ZATCA:

```
php artisan zatca:onboard --otp=123456 --solution-name=ERP --save
```

Or programmatically:

```
// Generate keys & CSR
$keys = Zatca::phase2()->generateKeysAndCsr($egsUnit, 'ERP');

// Issue compliance certificate with OTP from ZATCA portal
$result = Zatca::phase2()->issueComplianceCertificate($keys['csr'], $otp);

if ($result->success) {
    // Save these securely
    $certificate = $result->binarySecurityToken;
    $secret = $result->secret;
    $privateKey = $keys['private_key'];

    // Store in .env or database
    \Illuminate\Support\Facades\Env::set('ZATCA_CERTIFICATE', base64_encode($certificate));
    \Illuminate\Support\Facades\Env::set('ZATCA_SECRET', $secret);
    \Illuminate\Support\Facades\Env::set('ZATCA_PRIVATE_KEY', base64_encode($privateKey));
}
```

### Step 2: Sign &amp; Submit Invoice

[](#step-2-sign--submit-invoice)

```
// Build invoice data
$invoice = InvoiceDTO::fromArray([
    'invoice_serial_number' => 'EGS1-886431145-1',
    'invoice_counter_number' => 2,
    'issue_date' => '2024-01-01',
    'issue_time' => '14:40:40',
    'previous_invoice_hash' => '',
    'line_items' => [
        [
            'id' => '1',
            'name' => 'Product A',
            'quantity' => 10,
            'tax_exclusive_price' => 100.00,
            'vat_percent' => 0.15,
        ],
    ],
]);

$egsUnit = [
    'uuid' => '6f4d20e0-6bfe-4a80-9389-7dabe6620f12',
    'custom_id' => 'EGS1-886431145',
    'model' => 'Desktop',
    'vat_number' => '300000000000003',
    'vat_name' => 'شركة التقنية',
    'crn_number' => '454634645645654',
    'location' => [
        'city' => 'Riyadh',
        'city_subdivision' => 'West',
        'street' => 'King Fahd Road',
        'building' => '1234',
        'plot_identification' => '0000',
        'postal_zone' => '11564',
    ],
    'branch_name' => 'Main Branch',
    'branch_industry' => 'Retail',
];

// 1. Sign invoice (generates XML + hash + QR)
$signed = Zatca::phase2()->signInvoice(
    invoice: $invoice,
    egsUnit: $egsUnit,
    certificate: $certificate,
    privateKey: $privateKey,
);

// 2. Submit to ZATCA (auto-detects sandbox vs production)
$result = Zatca::phase2()->submitInvoice(
    signedInvoiceXml: $signed['signed_xml'],
    invoiceHash: $signed['invoice_hash'],
    certificate: $certificate,
    secret: $secret,
);

if ($result->success) {
    echo 'Invoice submitted successfully! Request ID: ' . $result->requestID;
}
```

### Using Queue for Async Sync

[](#using-queue-for-async-sync)

```
use Aghfatehi\Zatca\Jobs\SyncInvoiceToZatcaJob;

SyncInvoiceToZatcaJob::dispatch(
    invoiceData: $invoice->toArray(),
    egsUnit: $egsUnit,
    certificate: $certificate,
    privateKey: $privateKey,
    secret: $secret,
);
```

---

QR Code Display on PDF / View
-----------------------------

[](#qr-code-display-on-pdf--view)

### Method 1: Blade View (Direct Rendering)

[](#method-1-blade-view-direct-rendering)

**1. In the Controller — generate QR TLV:**

```
