laravel-zatca maintained by saudizatca
Description
Complete Laravel package for ZATCA (Saudi Arabia) E-Invoicing Phase 2 integration - Supports Sandbox, Simulation, and Production environments
Author
Last update
2026/05/04 23:46
(dev-main)
License
Downloads
5
Tags
ZATCA E-Invoicing Laravel Package
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.