zid / zatca
ZATCA E-Invoicing integration tools
Requires
- php: ^8.1
- ext-bcmath: *
- ext-dom: *
- ext-json: *
- ext-openssl: *
- ext-simplexml: *
- ext-xsl: *
- guzzlehttp/guzzle: ^7.2
Requires (Dev)
- phpunit/phpunit: ^9.0
This package is auto-updated.
Last update: 2026-04-09 14:53:46 UTC
README
๐งพ ZATCA E-Invoicing Phase 2
PHP Package for Saudi Arabia's ZATCA (Fatoora) Integration
Simplifies Phase 2 e-invoicing requirements including certificate generation, invoice signing, QR code generation, and submission to ZATCA's API
View Examples โข Report a Bug
Features
- Certificate Management: Generate CSR (Certificate Signing Request) and obtain compliance/production certificates
- Invoice Processing: Hash and sign XML invoices according to ZATCA specifications
- QR Code Generation: Create compliant QR codes for both simplified and standard invoices
- Compliance Validation: Check invoice compliance before production submission
- Invoice Submission: Submit invoices to ZATCA via Reporting (simplified) or Clearance (standard) APIs
- Multi-Environment Support: Sandbox, Simulation, and Production environments
- Clean Architecture: Well-structured, maintainable, and testable code
Requirements
- PHP 8.1 or higher
- Required PHP extensions:
ext-opensslext-domext-xslext-jsonext-bcmathext-simplexml
Installation
Install the package via Composer:
composer require zid/zatca
Quick Start
1. Generate Certificate Signing Request (CSR)
First, generate a CSR and private key for your organization:
<?php require_once 'vendor/autoload.php'; use Zid\Zatca\CertificateSigningRequestBuilder; $csrBuilder = new CertificateSigningRequestBuilder(); $csrBuilder ->setCommonName('TST-886431145-311111111101113') ->setSerialNumber('TST', 'TST', 'ed22f1d8-e6a2-1118-9b58-d9a8f11e445f') ->setOrganizationIdentifier('311111111101113') ->setOrganizationalUnitName('Riyadh Branch') ->setOrganizationName('ABCD Limited') ->setCountry('SA') ->setInvoiceType('1100') ->setAddress('RRRD2929') ->setBusinessCategory('Technology') ->generate(); // Save CSR and private key $csrBuilder->saveCsr('certificate.csr'); $csrBuilder->savePrivateKey('private.pem');
2. Request Compliance Certificate
Obtain a compliance certificate from ZATCA using your CSR and OTP:
<?php use Zid\Zatca\ComplianceService; use Zid\Zatca\Enums\ZatcaEnvironment; $complianceService = new ComplianceService(ZatcaEnvironment::SANDBOX); $csr = file_get_contents('certificate.csr'); $ccsid = $complianceService->requestComplianceCertificate( b64Csr: base64_encode($csr), otp: '123456' ); // Save compliance certificate $ccsid->saveAsJson('ccsid.json'); echo "Certificate: " . $ccsid->certificate . PHP_EOL; echo "Secret: " . $ccsid->secret . PHP_EOL;
3. Hash Invoice XML
Hash your unsigned invoice XML:
<?php use Zid\Zatca\InvoiceHashingService; $xmlContent = file_get_contents('unsigned_invoice.xml'); $hashingService = new InvoiceHashingService(); $result = $hashingService->hash($xmlContent); echo "Invoice Hash: " . $result->invoiceHash . PHP_EOL; echo "UUID: " . $result->uuid . PHP_EOL; // Save for later use file_put_contents('invoice.json', json_encode($result, JSON_PRETTY_PRINT));
4. Sign Invoice
Sign the invoice with your private key and compliance certificate:
<?php use Zid\Zatca\InvoiceSigningService; use Zid\Zatca\GetDigitalSignatureService; use Zid\Zatca\GetPublicKeyAndSignatureService; use Zid\Zatca\QrCodeGeneratorService; use Zid\Zatca\Entities\CSID; $invoiceData = json_decode(file_get_contents('invoice.json'), true); $canonicalXml = base64_decode($invoiceData['base64CanonicalXml']); $invoiceHash = $invoiceData['invoiceHash']; $ccsid = CSID::loadFromJson('ccsid.json'); $privateKey = file_get_contents('private.pem'); $privateKey = str_replace(["\n", "\t", "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----"], '', $privateKey); $digitalSignatureService = new GetDigitalSignatureService(); $publicKeyService = new GetPublicKeyAndSignatureService(); $qrCodeService = new QrCodeGeneratorService($publicKeyService); $signingService = new InvoiceSigningService($digitalSignatureService, $qrCodeService); $result = $signingService->sign( csid: $ccsid, privateKeyContent: $privateKey, canonicalXml: $canonicalXml, invoiceHash: $invoiceHash ); echo "Signed Invoice (Base64): " . $result->b64SignedInvoice . PHP_EOL; echo "QR Code (Base64): " . $result->b64QrCode . PHP_EOL;
5. Check Compliance
Validate your signed invoice against ZATCA's compliance checks:
<?php use Zid\Zatca\ComplianceService; use Zid\Zatca\Enums\ZatcaEnvironment; use Zid\Zatca\Entities\CSID; $complianceService = new ComplianceService(ZatcaEnvironment::SANDBOX); $ccsid = CSID::loadFromJson('ccsid.json'); $result = $complianceService->checkCompliance( binarySecurityToken: $ccsid->certificate, secret: $ccsid->secret, invoiceHash: 'YOUR_INVOICE_HASH', invoiceUuid: 'YOUR_INVOICE_UUID', signedInvoice: 'BASE64_SIGNED_INVOICE' ); echo "Validation Status: " . $result->validationResults->status . PHP_EOL; echo "Clearance Status: " . $result->clearanceStatus . PHP_EOL; if (!empty($result->validationResults->errorMessages)) { echo "Errors:" . PHP_EOL; print_r($result->validationResults->errorMessages); }
6. Generate Production Certificate
After successful compliance validation, request a production certificate:
<?php use Zid\Zatca\ProductionCsidGeneratorService; use Zid\Zatca\Enums\ZatcaEnvironment; use Zid\Zatca\Entities\CSID; $productionService = new ProductionCsidGeneratorService(ZatcaEnvironment::SANDBOX); $ccsid = CSID::loadFromJson('ccsid.json'); $pcsid = $productionService->requestProductionCertificate( binarySecurityToken: $ccsid->certificate, secret: $ccsid->secret, ccsidRequestId: $ccsid->requestId ); // Save production certificate $pcsid->saveAsJson('pcsid.json');
7. Submit Invoice to ZATCA
Submit your signed invoice to ZATCA (Reporting for simplified, Clearance for standard):
<?php use Zid\Zatca\InvoiceSubmissionService; use Zid\Zatca\Enums\ZatcaEnvironment; use Zid\Zatca\Entities\CSID; $submissionService = new InvoiceSubmissionService(ZatcaEnvironment::PRODUCTION); $pcsid = CSID::loadFromJson('pcsid.json'); $response = $submissionService->submit( csid: $pcsid, isSimplified: true, // false for standard invoices invoiceHash: 'YOUR_INVOICE_HASH', invoiceUuid: 'YOUR_INVOICE_UUID', invoiceXml: 'YOUR_SIGNED_INVOICE_XML' ); if ($response->isSubmitted) { echo "Invoice submitted successfully!" . PHP_EOL; echo "Status: " . $response->status . PHP_EOL; } else { echo "Submission failed!" . PHP_EOL; print_r($response->validationResults->errorMessages); }
Environment Configuration
The package supports three ZATCA environments:
use Zid\Zatca\Enums\ZatcaEnvironment; // Sandbox - For development and testing ZatcaEnvironment::SANDBOX // Simulation - For pre-production testing ZatcaEnvironment::SIMULATION // Production - For live invoices ZatcaEnvironment::PRODUCTION
Using the Facade (Alternative Approach)
The Zatca facade provides a cleaner, more convenient API for accessing all services. Instead of manually instantiating services and their dependencies, you can use the facade as a single entry point.
Benefits of Using the Facade
- Simplified API: Single entry point for all ZATCA operations
- Lazy Loading: Services are only instantiated when needed
- Dependency Management: Automatically handles service dependencies
- Cleaner Code: Less boilerplate, more readable
Facade Example: Complete Workflow
<?php require_once 'vendor/autoload.php'; use Zid\Zatca\Zatca; use Zid\Zatca\Enums\ZatcaEnvironment; // Initialize the facade $zatca = new Zatca(ZatcaEnvironment::SANDBOX); // 1. Generate CSR $csrBuilder = $zatca->csrBuilder() ->setCommonName('TST-886431145-311111111101113') ->setSerialNumber('TST', 'TST', 'ed22f1d8-e6a2-1118-9b58-d9a8f11e445f') ->setOrganizationIdentifier('311111111101113') ->setOrganizationalUnitName('Riyadh Branch') ->setOrganizationName('ABCD Limited') ->setCountry('SA') ->setInvoiceType('1100') ->setAddress('RRRD2929') ->setBusinessCategory('Technology') ->generate(); $csrBuilder->saveCsr('certificate.csr'); $csrBuilder->savePrivateKey('private.pem'); // 2. Request compliance certificate $csr = file_get_contents('certificate.csr'); $ccsid = $zatca->compliance()->requestComplianceCertificate( b64Csr: base64_encode($csr), otp: '123456' ); $ccsid->saveAsJson('ccsid.json'); // 3. Hash invoice $invoiceXml = file_get_contents('unsigned_invoice.xml'); $hashingResult = $zatca->hashing()->hash($invoiceXml); // 4. Sign invoice $privateKey = file_get_contents('private.pem'); $privateKey = str_replace(["\n", "\t", "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----"], '', $privateKey); $signingResult = $zatca->signing()->sign( csid: $ccsid, privateKeyContent: $privateKey, canonicalXml: base64_decode($hashingResult->b64CanonicalXml), invoiceHash: $hashingResult->invoiceHash ); // 5. Check compliance $validationResponse = $zatca->compliance()->checkCompliance( binarySecurityToken: $ccsid->certificate, secret: $ccsid->secret, invoiceHash: $hashingResult->invoiceHash, invoiceUuid: $hashingResult->uuid, signedInvoice: $signingResult->b64SignedInvoice ); if ($validationResponse->validationResults->status === 'PASS') { // 6. Request production certificate $pcsid = $zatca->production()->requestProductionCertificate( binarySecurityToken: $ccsid->certificate, secret: $ccsid->secret, ccsidRequestId: $ccsid->requestId ); $pcsid->saveAsJson('pcsid.json'); // 7. Submit invoice to production $submissionResult = $zatca->submission()->submit( csid: $pcsid, isSimplified: true, invoiceHash: $hashingResult->invoiceHash, invoiceUuid: $hashingResult->uuid, invoiceXml: base64_decode($signingResult->b64SignedInvoice) ); if ($submissionResult->isSubmitted) { echo "Invoice submitted successfully!" . PHP_EOL; } }
Facade API Methods
The Zatca facade provides the following methods:
// Access services $zatca->compliance() // ComplianceService $zatca->production() // ProductionCsidGeneratorService $zatca->submission() // InvoiceSubmissionService $zatca->hashing() // InvoiceHashingService $zatca->signing() // InvoiceSigningService $zatca->qrCode() // QrCodeGeneratorService $zatca->csrBuilder() // CertificateSigningRequestBuilder $zatca->client() // ZatcaClient (for direct API access)
Comparison: Traditional vs Facade
Traditional Approach:
// Manual dependency injection $digitalSignatureService = new GetDigitalSignatureService(); $publicKeyService = new GetPublicKeyAndSignatureService(); $qrCodeService = new QrCodeGeneratorService($publicKeyService); $signingService = new InvoiceSigningService($digitalSignatureService, $qrCodeService); $result = $signingService->sign(...);
Facade Approach:
// Clean and simple $zatca = new Zatca(ZatcaEnvironment::SANDBOX); $result = $zatca->signing()->sign(...);
The facade handles all dependency injection automatically, making your code cleaner and easier to maintain.
Invoice Types
When generating CSR, specify the invoice type using a 4-digit code:
1100- Standard & Simplified Invoices0100- Simplified Invoice Only (B2C)1000- Standard Invoice Only (B2B) Each digit acts as a boolean flag:[Standard, Simplified, Future Use, Future Use]
API Reference
Core Services
CertificateSigningRequestBuilder
Generates CSR and private key for ZATCA onboarding.
Methods:
setCommonName(string $name)- Set common namesetSerialNumber(string $solutionProvider, string $solutionName, string $serialNumber)- Set device serial numbersetOrganizationIdentifier(string $id)- Set organization tax IDsetOrganizationalUnitName(string $name)- Set organizational unitsetOrganizationName(string $name)- Set organization namesetCountry(string $country)- Set country code (SA)setInvoiceType(string $type)- Set invoice type (e.g., '1100')setAddress(string $address)- Set business addresssetBusinessCategory(string $category)- Set business categorygenerate()- Generate CSR and private keygetCsr()- Get generated CSRgetPrivateKey()- Get generated private keysaveCsr(string $path)- Save CSR to filesavePrivateKey(string $path)- Save private key to file
ComplianceService
Handles compliance certificate requests and validation.
Methods:
requestComplianceCertificate(string $b64Csr, string $otp): CSIDcheckCompliance(string $binarySecurityToken, string $secret, string $invoiceHash, string $invoiceUuid, string $signedInvoice): ValidationResponse
InvoiceHashingService
Hashes invoice XML according to ZATCA specifications.
Methods:
hash(string $unsignedInvoiceXml): InvoiceHashingResult
InvoiceSigningService
Signs invoices with digital signature and generates QR codes.
Methods:
sign(CSID $csid, string $privateKeyContent, string $canonicalXml, string $invoiceHash): InvoiceSigningResult
QrCodeGeneratorService
Generates ZATCA-compliant QR codes.
Methods:
generate(CSID $csid, string $invoiceHash, string $canonicalXml, string $signatureValue): string
ProductionCsidGeneratorService
Requests production certificates after compliance validation.
Methods:
requestProductionCertificate(string $binarySecurityToken, string $secret, string $ccsidRequestId): CSID
InvoiceSubmissionService
Submits invoices to ZATCA via Reporting or Clearance APIs.
Methods:
submit(CSID $csid, bool $isSimplified, string $invoiceHash, string $invoiceUuid, string $invoiceXml): SubmissionResponse
Entities
CSID
Represents a Certificate Signing ID (compliance or production certificate).
Properties:
string $certificate- Base64 encoded certificatestring $secret- Certificate secretstring $requestId- Request ID from ZATCA
Methods:
static loadFromJson(string $filepath): selfsaveAsJson(string $filepath): void
InvoiceHashingResult
Result of invoice hashing operation.
Properties:
string $invoiceHash- Base64 encoded SHA-256 hashstring $uuid- Invoice UUIDstring $b64Invoice- Base64 encoded invoicestring $b64CanonicalXml- Base64 encoded canonical XML
InvoiceSigningResult
Result of invoice signing operation.
Properties:
string $signature- Digital signaturestring $b64SignedInvoice- Base64 encoded signed invoicestring $b64QrCode- Base64 encoded QR code
SubmissionResponse
Response from invoice submission to ZATCA.
Properties:
ValidationResults $validationResults- Validation messagesstring $status- Submission status (REPORTED/CLEARED)bool $isSubmitted- Whether submission was successful
ValidationResponse
Response from compliance validation.
Properties:
ValidationResults $validationResults- Validation messagesstring|null $reportingStatus- Reporting statusstring|null $clearanceStatus- Clearance statusstring|null $qrSellerStatus- QR seller statusstring|null $qrBuyerStatus- QR buyer status
ValidationResults
Validation messages from ZATCA.
Properties:
array $infoMessages- Informational messagesarray $warningMessages- Warning messagesarray $errorMessages- Error messagesstring $status- Overall validation status
Examples
Complete working examples are available in the examples/ directory:
0_using_facade.php- Using the Zatca Facade (Recommended)1_generate_csr.php- Generate CSR and private key2_generate_compliance_csid.php- Request compliance certificate3_hash_invoice_xml.php- Hash invoice XML4_generate_qr_code_xml.php- Generate QR code5_sign_invoice_xml.php- Sign invoice6_check_compliance.php- Validate compliance7_generate_production_csid.php- Request production certificate
Testing
Run the test suite:
composer test
Or use PHPUnit directly:
vendor/bin/phpunit
Error Handling
The package throws specific exceptions for different error scenarios:
use Zid\Zatca\Exceptions\ZatcaApiException; use Zid\Zatca\Exceptions\InvoiceHashingException; use Zid\Zatca\Exceptions\QrGenerationException; try { // Your code here } catch (ZatcaApiException $e) { // Handle API errors echo "API Error: " . $e->getMessage(); } catch (InvoiceHashingException $e) { // Handle hashing errors echo "Hashing Error: " . $e->getMessage(); } catch (QrGenerationException $e) { // Handle QR generation errors echo "QR Error: " . $e->getMessage(); }
Best Practices
- Store Certificates Securely: Keep your private keys and certificates in secure storage
- Use Environment Variables: Store sensitive data like OTPs and secrets in environment variables
- Validate Before Submission: Always check compliance before submitting to production
- Handle Errors Gracefully: Implement proper error handling and logging
- Test in Sandbox: Thoroughly test your integration in the sandbox environment
- Keep Certificates Updated: Monitor certificate expiration and renew as needed
ZATCA Integration Workflow
1. Generate CSR + Private Key
โ
2. Request Compliance Certificate (with OTP)
โ
3. Hash Invoice XML
โ
4. Sign Invoice
โ
5. Generate QR Code
โ
6. Check Compliance
โ
7. Request Production Certificate
โ
8. Submit Invoices to Production
Resources
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This package is open-sourced software licensed under the MIT License.
Credits
Developed and maintained by Zid
Support
For issues, questions, or contributions, please visit the GitHub repository.
Disclaimer: This is an unofficial package and is not affiliated with or endorsed by ZATCA. Use at your own risk and ensure compliance with all ZATCA regulations.