saudizatca / laravel-zatca
Complete Laravel package for ZATCA (Saudi Arabia) E-Invoicing Phase 2 integration - Supports Sandbox, Simulation, and Production environments
v1.1.2
2026-05-04 00:14 UTC
Requires
- php: ^8.1
- ext-curl: *
- ext-dom: *
- ext-gmp: *
- ext-json: *
- ext-mbstring: *
- ext-openssl: *
- ext-xmlwriter: *
- ext-zip: *
- illuminate/console: ^10.0|^11.0|^12.0|^13.0
- illuminate/database: ^10.0|^11.0|^12.0|^13.0
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0|^10.0|^11.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0|^11.0|^12.0
- squizlabs/php_codesniffer: ^3.7
README
Complete Laravel package for ZATCA (Saudi Arabia) E-Invoicing Phase 2 integration. Supports all three environments: Sandbox, Simulation, and Production.
Features
- Certificate Management: CSR generation with secp256k1 ECC keys
- Compliance CSID: Request compliance certificates from ZATCA
- Production CSID: Request production certificates after passing compliance
- Invoice Generation: UBL 2.1 compliant XML for all invoice types
- Digital Signing: ECDSA SHA-256 signatures (XAdES-BES)
- QR Code Generation: ZATCA TLV format (Phase 1 & Phase 2)
- Invoice Submission: Reporting (B2C) and Clearance (B2B)
- Credit/Debit Notes: Full support for invoice adjustments
- Arabic Support: Bilingual invoice support
- Multi-Environment: Sandbox, Simulation, and Production
- Comprehensive Logging: Detailed logging of all operations
- Database Storage: Track all invoices and certificates
- Full Test Coverage: Unit and Feature tests included
Requirements
- PHP 8.1+
- Laravel 10.x / 11.x / 12.x
- OpenSSL extension with EC support
- GMP extension (recommended)
- ext-dom, ext-mbstring, ext-json, ext-xmlwriter, ext-curl
Installation
composer require saudizatca/laravel-zatca
Publish configuration:
php artisan vendor:publish --tag=zatca-config
Run migrations:
php artisan migrate
Configuration
Add to your .env file:
# Environment: sandbox | simulation | production ZATCA_ENVIRONMENT=sandbox # Seller Information ZATCA_SELLER_NAME_EN="Your Company Name" ZATCA_SELLER_NAME_AR="اسم شركتك بالعربي" ZATCA_VAT_NUMBER=300000000000003 # Address ZATCA_SELLER_STREET="King Fahd Road" ZATCA_SELLER_BUILDING="1234" ZATCA_SELLER_CITY="Riyadh" ZATCA_SELLER_DISTRICT="Al Olaya" ZATCA_SELLER_POSTAL_CODE="12345" # CSR Configuration ZATCA_CSR_ORGANIZATION="Your Company Name" ZATCA_CSR_ORGANIZATION_UNIT="IT Department" ZATCA_CSR_COMMON_NAME="Your Company Name" # Sandbox Credentials (from ZATCA Developer Portal) ZATCA_SANDBOX_USERNAME=your_sandbox_username ZATCA_SANDBOX_PASSWORD=your_sandbox_password # Debug (optional) ZATCA_DEBUG_ENABLED=true
Quick Start
1. Check Status
php artisan zatca:status
2. Generate CSR
php artisan zatca:csr --vat=300000000000003 --org="Your Company"
3. Request Compliance CSID
Get OTP from ZATCA portal, then:
php artisan zatca:compliance-csid --otp=123456
4. Request Production CSID (after compliance tests pass)
php artisan zatca:production-csid
5. Submit Invoices
# Simplified invoice (B2C) php artisan zatca:report --number=INV-001 --total=115 --vat=15 # Standard invoice (B2B) - requires XML file php artisan zatca:clear --xml=/path/to/signed_invoice.xml
Programmatic Usage
Generate CSR
use SaudiZATCA\Facades\Zatca; $result = Zatca::certificate()->generateCSR([ 'organization_identifier' => '300000000000003', 'organization' => 'Your Company', 'common_name' => 'Your Company', 'street' => 'King Fahd Road', 'city' => 'Riyadh', ]); // $result['csr'] - CSR content // $result['private_key'] - Private key content
Create and Submit Invoice
use SaudiZATCA\Facades\Zatca; use SaudiZATCA\Data\InvoiceData; use SaudiZATCA\Data\InvoiceLineData; use SaudiZATCA\Data\SellerData; use SaudiZATCA\Data\BuyerData; // Create seller $seller = SellerData::fromConfig(config('zatca.seller')); // Create buyer (for B2B/standard invoices) $buyer = new BuyerData( name: 'Buyer Company', vatNumber: '300000000000004', city: 'Jeddah' ); // Create invoice $invoice = new InvoiceData( invoiceNumber: 'INV-001', issueDate: new DateTime(), lines: [ new InvoiceLineData('Product A', 2, 50.0, 15.0), new InvoiceLineData('Product B', 1, 100.0, 15.0), ], type: InvoiceData::TYPE_STANDARD // or TYPE_SIMPLIFIED ); // Process (generate XML, sign, QR, submit) $result = Zatca::processInvoice($invoice, $seller, $buyer); // $result['uuid'] // $result['invoice_hash'] // $result['signed_xml'] // $result['qr_code'] // $result['submission']
Generate QR Code (Phase 1 - Basic)
use SaudiZATCA\Facades\Zatca; use SaudiZATCA\Data\SellerData; $seller = new SellerData('Your Company', '300000000000003'); $qrCode = Zatca::generatePhase1QR($seller, 115.0, 15.0); // Returns Base64-encoded TLV QR data
Working with Existing XML
use SaudiZATCA\Facades\Zatca; // Generate XML only $xml = Zatca::xml()->generate($invoice, $seller, $buyer); // Sign existing XML $signedResult = Zatca::invoice()->signInvoice($xml, $invoice); // Generate QR for signed invoice $qrCode = Zatca::invoice()->generateQRCode($seller, $invoice, $signedResult['invoice_hash'], $signedResult); // Submit to ZATCA $submission = Zatca::invoice()->submitToZatca($signedResult['signed_xml'], $signedResult['invoice_hash'], $invoice);
Invoice Types
| Type | Description | Submission Method |
|---|---|---|
standard |
B2B Tax Invoice | Clearance (real-time) |
simplified |
B2C Simplified Invoice | Reporting (within 24h) |
credit_note |
Credit Note | Clearance |
debit_note |
Debit Note | Clearance |
Artisan Commands
| Command | Description |
|---|---|
zatca:status |
Check integration status |
zatca:csr |
Generate CSR |
zatca:compliance-csid |
Request compliance CSID |
zatca:production-csid |
Request production CSID |
zatca:report |
Submit simplified invoice |
zatca:clear |
Submit standard invoice |
zatca:validate |
Validate XML or QR code |
Database Models
ZatcaCertificate
Stores certificate information:
use SaudiZATCA\Models\ZatcaCertificate; // Get active production certificate $cert = ZatcaCertificate::active() ->environment('production') ->first(); // Check validity if ($cert && $cert->isValid()) { // Use certificate }
ZatcaInvoice
Tracks all invoices:
use SaudiZATCA\Models\ZatcaInvoice; // Get pending invoices $pending = ZatcaInvoice::pending()->get(); // Get today's invoices $today = ZatcaInvoice::today()->get(); // Get by status $submitted = ZatcaInvoice::status('submitted')->get();
ZatcaLog
Detailed operation logs:
use SaudiZATCA\Models\ZatcaLog; // Get recent errors $errors = ZatcaLog::errors()->recent(24)->get(); // Get API logs $apiLogs = ZatcaLog::category('api')->recent()->get();
Environments
Sandbox
- For initial development and testing
- Uses ZATCA Developer Portal
- Pre-configured test credentials
Simulation
- Pre-production testing
- Requires real CSID from compliance
- Tests with real API structure
Production
- Live environment
- Requires production CSID
- Real invoice submission
Testing
Run the test suite:
# Run all tests vendor/bin/phpunit # With coverage vendor/bin/phpunit --coverage-html coverage # Run specific test vendor/bin/phpunit --filter=CertificateServiceTest
Test Structure
tests/
├── Unit/
│ ├── CertificateServiceTest.php
│ ├── InvoiceServiceTest.php
│ └── QRCodeServiceTest.php
└── Feature/
├── APIIntegrationTest.php
└── InvoiceSubmissionTest.php
Error Handling
All exceptions extend ZatcaException:
use SaudiZATCA\Exceptions\ZatcaException; use SaudiZATCA\Exceptions\CertificateException; use SaudiZATCA\Exceptions\APIException; use SaudiZATCA\Exceptions\InvoiceException; try { $result = Zatca::processInvoice($invoice, $seller); } catch (CertificateException $e) { // Handle certificate errors Log::error('Certificate: ' . $e->getMessage()); } catch (APIException $e) { // Handle API errors Log::error('API Error (' . $e->getStatusCode() . '): ' . $e->getMessage()); if ($e->getDetails()) { Log::error('Details: ' . json_encode($e->getDetails())); } } catch (InvoiceException $e) { // Handle invoice errors Log::error('Invoice: ' . $e->getMessage()); } catch (ZatcaException $e) { // Handle general ZATCA errors Log::error('ZATCA: ' . $e->getMessage()); }
Logging
Configure logging in config/zatca.php:
'logging' => [ 'enabled' => true, 'channel' => 'zatca', // Create this channel in logging.php 'level' => 'debug', 'log_api_requests' => true, 'log_api_responses' => true, 'log_sensitive_data' => false, // Set false in production ],
Add to config/logging.php:
'channels' => [ 'zatca' => [ 'driver' => 'single', 'path' => storage_path('logs/zatca.log'), 'level' => 'debug', ], ],
Security
- Never commit
.envfiles with real credentials - Use
log_sensitive_data: falsein production - Store certificates securely (storage path should be outside web root)
- Rotate certificates before expiry
- Use HTTPS for all API communications in production
Troubleshooting
Certificate Issues
# Check OpenSSL EC support php -r "var_dump(openssl_get_curve_names());" # Verify CSR content openssl req -in storage/zatca/certificates/csr.pem -text -noout
API Connection Issues
# Check ZATCA status php artisan zatca:status # Test with debug enabled ZATCA_DEBUG_ENABLED=true php artisan zatca:report --number=TEST
Contributing
- Fork the repository
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
This package is open-sourced software licensed under the MIT license.
Support
For issues and feature requests, please use the GitHub issue tracker.