Download the PHP package corecave/laravel-zatca without Composer
On this page you can find all versions of the php package corecave/laravel-zatca. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download corecave/laravel-zatca
More information about corecave/laravel-zatca
Files in corecave/laravel-zatca
Package laravel-zatca
Short Description Laravel package for ZATCA e-invoicing integration (Saudi Arabia Phase 2)
License MIT
Informations about the package laravel-zatca
Laravel ZATCA
A comprehensive Laravel package for integrating with Saudi Arabia's ZATCA (Zakat, Tax and Customs Authority) e-invoicing system (FATOORA platform).
This package supports Phase 2 requirements including:
- CSR generation and certificate management
- Invoice XML generation (UBL 2.1 compliant)
- Digital signing with ECDSA (secp256k1)
- QR code generation (9 TLV tags)
- Invoice reporting (B2C simplified invoices)
- Invoice clearance (B2B standard invoices)
- Credit and debit note handling
- Sandbox, simulation, and production environments
Requirements
- PHP 8.3+, which Laravel 13 needs
- Laravel 13.x
- OpenSSL extension
- GMP extension (recommended for better performance)
Installation
The package is on Packagist:
Publish the configuration file:
The package ships no migrations. Each workshop keeps its own certificates, invoice counter and hash chain in its own schema, so the host app keeps the two table migrations with its workshop migrations (database/migrations/tenant in Syanat) and runs them per workshop:
An app whose one seller keeps its device centrally, while a tenant's connection is the default, keeps the two tables with its central migrations instead and names its central connection in ZATCA_DB_CONNECTION: the certificates, the chain and the chain's lock all use it.
Configuration
Add these environment variables to your .env file:
Environments
The package supports three environments:
| Environment | Endpoint | Certificate Issuer | Purpose |
|---|---|---|---|
sandbox |
developer-portal | CN=eInvoicing (mock) |
Basic development testing |
simulation |
simulation | CN=TSZEINVOICE-SubCA-1, DC=extgazt, DC=gov, DC=local |
Real testing with ZATCA |
production |
core | CN=PEZEINVOICESCA2-CA, DC=extgazt, DC=gov, DC=local |
Live production |
Important:
- The
sandboxenvironment returns mock certificates that will NOT pass ZATCA's official validators - Use
simulationfor testing with the ZATCA validator at https://sandbox.zatca.gov.sa/Compliance - Use
productiononly when ready to go live
Onboarding Process
Step 1: Generate CSR
Step 2: Get Compliance CSID
- Log in to the FATOORA portal
- Generate an OTP for your EGS unit
- Run the compliance command:
Step 3: Get Production CSID
After passing compliance checks:
Usage
Creating a Simplified Invoice (B2C)
Creating a Standard Invoice (B2B)
For standard B2B invoices, buyer information is required and must include complete address details for Saudi Arabian buyers.
Buyer Identification Schemes
For the registration_scheme field, ZATCA accepts:
| Scheme ID | Description |
|---|---|
CRN |
Commercial Registration Number |
MOM |
Momra License |
MLS |
MLSD License |
SAG |
Sagia License |
NAT |
National ID (10 digits) |
GCC |
GCC ID |
IQA |
Iqama Number |
TIN |
Tax Identification Number (VAT) |
700 |
700 Number |
OTH |
Other ID |
Required Buyer Address Fields for Saudi Arabia (BR-KSA-63)
When the buyer's country is SA, these fields are mandatory:
| Field | XML Element | Description |
|---|---|---|
street |
cbc:StreetName |
Street name (BT-50) |
building |
cbc:BuildingNumber |
Building number - 4 digits (KSA-18) |
postal_code |
cbc:PostalZone |
Postal code - 5 digits (BT-53) |
city |
cbc:CityName |
City name (BT-52) |
district |
cbc:CitySubdivisionName |
District name (KSA-4) |
country |
cbc:IdentificationCode |
Country code (BT-55) |
Creating Credit/Debit Notes
Auto-Processing Invoices
The process() method automatically determines whether to report or clear:
VAT Categories
Working with Certificates
Manual XML Generation
Hash Chain Management
Artisan Commands
Events
The package dispatches events you can listen to:
InvoiceReported- When a simplified invoice is successfully reportedInvoiceCleared- When a standard invoice is successfully clearedInvoiceRejected- When an invoice is rejected by ZATCACertificateExpiring- When a certificate is about to expire
Debugging
Enable debug mode to save XML files and hashes for inspection:
Debug files are saved to storage/app/{ZATCA_DEBUG_PATH}/:
{invoice}_unsigned.xml- XML before signing{invoice}_signed.xml- XML after signing{invoice}_hash.txt- Invoice hash{invoice}_qr.txt- QR code data
Error Handling
Common ZATCA Validation Errors
| Error Code | Message | Solution |
|---|---|---|
X509IssuerName |
wrong X509IssuerName | Use simulation or production environment to get real certificates |
X509SerialNumber |
wrong X509SerialNumber | Certificate not from ZATCA - regenerate with real OTP |
BR-KSA-F-13 |
Invalid Seller/Buyer ID | Provide valid registration_number with correct registration_scheme |
BR-KSA-63 |
Missing address fields | Include all required fields: street, building, postal_code, city, district |
BR-CL-KSA-14 |
QR Code exceeds 1000 chars | Reduce invoice data or check QR generation |
Changelog
v2.1.0 (2026-10-17)
Added
zatca.connection(ZATCA_DB_CONNECTION): the connectionZatcaCertificateandZatcaInvoiceuse andHashChainManagertakes the chain's lock on, through the newHashChainManager::connection(); the compliance samples read their place in the chain there too. Empty, as before, everything stays on the default connection.
v2.0.0 (2026-10-17)
Changed
Every method now takes at most three parameters, so the long parameter lists moved into named value objects. The XML, hashes, QR codes and signatures the package produces are unchanged. Callers change as follows:
Zatca::generateQrCode($invoice, $signatureValue, $publicKey, $certificateSignature)is nowZatca::generateQrCode($invoice, new QrSignature($signatureValue, $publicKey, $certificateSignature)), andQrGenerator::generate()takes the same two arguments.new Invoice(...)takes oneInvoiceDataandnew LineItem(...)oneLineItemData: set their public properties by name.InvoiceBuilderandLineItem::fromArray()work as before.new Certificate($type, $certificate, $privateKey, $secret, $requestId, $issuedAt, $expiresAt, $active, $metadata)is nownew Certificate(new CertificateOrigin($type, $requestId, $metadata), new CertificateCredentials($certificate, $privateKey, $secret), new CertificateLifetime($issuedAt, $expiresAt, $active)).Certificate::fromApiResponse()andCertificate::fromArray()work as before.CertificateManager::import($type, $certificatePath, $privateKeyPath, $secret, $requestId)is nowimport(new CertificateOrigin($type, $requestId), new CertificateFiles($certificatePath, $privateKeyPath), $secret).CsrGenerator::generateWithSerial($companyName, $version, $uuid, $config)is nowgenerateWithSerial(new EgsSerialNumber($companyName, $version, $uuid), $config).HashChainManager::recordInvoice(...)takes oneInvoiceRecord: set its public properties by name.updateInvoiceStatus($uuid, $status, $zatcaResponse, $signedXml, $qrCode)is nowupdateInvoiceStatus($uuid, $status, new StatusUpdate($zatcaResponse, $signedXml, $qrCode)).DebugDumper::dumpAll($invoiceId, $unsignedXml, $signedXml, $qrCode, $hash)is nowdumpAll($invoiceId, new InvoiceDocuments($unsignedXml, $signedXml, $qrCode), $hash).new ReportResult($invoice, $signedXml, $qrCode, $response)is nownew ReportResult(new Submission($invoice, $response), $signedXml, $qrCode), andClearanceResultlikewise.ZatcaExceptionhas no constructor of its own: build one with context throughZatcaException::withContext($message, $context).ApiException's constructor no longer takes the ZATCA errors and warnings;ApiException::fromResponse()reads them from the response.UblGeneratorwrites the parties, totals and lines throughUblPartyWriter,UblTotalsWriterandUblLineWriter; its public methods are unchanged.
Added
InvoiceBuilder::fromConfig()builds anInvoiceBuilderfrom thezatca.sellerandzatca.invoiceconfig, which the service provider and the builder's own static constructors used to read separately.
v1.1.0 (2024-12-13)
Fixed
- X509IssuerName format: Now correctly uses RFC 4514 format with
,(comma + space) separators matching ZATCA SDK - X509SerialNumber: Properly extracted from certificate
- SignedProperties hash: XML whitespace now matches Python SDK's exact format for correct hash computation
- Buyer PartyIdentification: Now always includes
<cac:PartyIdentification>element with proper schemeID - Buyer postal address: Now includes all required SA address fields (BuildingNumber, District, etc.)
Changed
Certificate::getFormattedIssuer()no longer reverses DN orderXmlSigner::formatIssuerDN()preserves,separatorsXmlSigner::computeSignedPropertiesHashSdkStyle()uses exact SDK whitespaceXmlSigner::buildSignatureXml()matches SDK indentation structureUblGenerator::addCustomerParty()always adds buyer ID, uses VAT as TIN fallback
Added
- Support for flat buyer data with all SA-required address fields
- Automatic schemeID detection (TIN for VAT numbers, NAT for national IDs, CRN for registration numbers)
v1.0.0 (2024-12-12)
- Initial release with full Phase 2 support
License
MIT License. See LICENSE for more information.
Resources
All versions of laravel-zatca with dependencies
illuminate/support Version ^13.0
illuminate/database Version ^13.0
phpseclib/phpseclib Version ^3.0
robrichards/xmlseclibs Version ^3.1
sabre/xml Version ^4.0
guzzlehttp/guzzle Version ^7.0|^8.0