https://github.com/saleh7/php-zatca-xml
PHP-ZATCA-XML is an unofficial PHP library for generating ZATCA Fatoora e-invoices. It simplifies the process of creating compliant e-invoices, generating QR codes, handling certificates, and submitting invoices to ZATCA’s servers.
https://github.com/saleh7/php-zatca-xml
certificates-generator e-invoices fatoora invoice php qrcode xml zatca
Last synced: 25 days ago
JSON representation
PHP-ZATCA-XML is an unofficial PHP library for generating ZATCA Fatoora e-invoices. It simplifies the process of creating compliant e-invoices, generating QR codes, handling certificates, and submitting invoices to ZATCA’s servers.
- Host: GitHub
- URL: https://github.com/saleh7/php-zatca-xml
- Owner: Saleh7
- License: mit
- Created: 2023-01-09T15:29:45.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2025-02-27T21:45:18.000Z (2 months ago)
- Last Synced: 2025-04-01T16:59:59.117Z (about 1 month ago)
- Topics: certificates-generator, e-invoices, fatoora, invoice, php, qrcode, xml, zatca
- Language: PHP
- Homepage:
- Size: 199 KB
- Stars: 29
- Watchers: 6
- Forks: 16
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
![]()
Please feel free to contribute if you are missing features or tags
View Examples
·
Report a bug
·
Request a feature
·
Ask questions## 📖 Introduction
**PHP-ZATCA-XML** is an unofficial PHP library for generating **ZATCA Fatoora** e-invoices. It simplifies the process of creating compliant e-invoices, generating QR codes, handling certificates, and submitting invoices to **ZATCA’s servers**.
Designed for **easy integration**, this library provides developers with a **customizable, robust, and efficient toolkit** to automate the ZATCA e-invoicing process in PHP applications.
## 🚀 Planned Features
We are actively working on expanding the capabilities of this library. If you're a developer and would like to contribute, your help is highly appreciated! 💡
- [ ] **XML to JSON Conversion** – Support for converting invoices from XML to JSON format.
- [ ] **JSON/Array to Invoice** – Ability to generate invoices directly from JSON or array structures.
- [ ] **Simplified Invoice Creation** – Streamlined generation of **Simplified Invoices**, **Debit**, and **Credit** compliant with ZATCA simplified.
- [ ] **Standard Invoice Creation** – Streamlined generation **Standard Invoices**, **Debit**, and **Credit** compliant with ZATCA standards.
- [ ] **Invoice to PDF Conversion** – Generate PDF versions of invoices for easy sharing and record-keeping.💡 **Got an idea?** Feel free to suggest it or contribute!
Let's build something great together! 🚀## ✨ Features
- 🚀 **ZATCA-Compliant** – Easily generate valid e-invoices for ZATCA regulations
- 📜 **Invoice Creation** – Generate standard and simplified invoices in XML format
- 🔐 **Digital Signing** – Sign invoices securely to ensure compliance
- 🏷 **QR Code Generation** – Automatically generate QR codes for invoices
- 📡 **Direct Submission to ZATCA** – Send invoices directly to ZATCA’s servers
- ⚡ **Lightweight & Fast** – Optimized for performance and easy integration in PHP projects
- 🔄 **Customizable & Extensible** – Easily adapt the library to your needs## 📌 Requirements
### ✅ PHP Version
- **PHP 8.1 or higher**### ✅ Required PHP Extensions
Ensure the following PHP extensions are installed and enabled:
- **`ext-dom`**
- **`ext-libxml`**
- **`ext-openssl`**
- **`ext-hash`**
- **`ext-mbstring`**## 🛠 Installation
```bash
composer require saleh7/php-zatca-xml
```## 🚀 Usage
This library simplifies the process of generating **ZATCA-compliant** e-invoices, handling **certificates**, signing invoices, and submitting them to **ZATCA’s API**. Below are the main usage examples:
---
### 📜 **1. Generating a Compliance Certificate**
First, generate a **certificate signing request (CSR)** and private key:
```php
use Saleh7\Zatca\CertificateBuilder;
use Saleh7\Zatca\Exceptions\CertificateBuilderException;try {
(new CertificateBuilder())
->setOrganizationIdentifier('312345678901233') // The Organization Identifier must be 15 digits, starting andending with 3
// string $solutionName .. The solution provider name
// string $model .. The model of the unit the stamp is being generated for
// string $serialNumber .. # If you have multiple devices each should have a unique serial number
->setSerialNumber('Saleh', '1n', 'SME00023')
->setCommonName('My Organization') // The common name to be used in the certificate
->setCountryName('SA') // The Country name must be Two chars only
->setOrganizationName('My Company') // The name of your organization
->setOrganizationalUnitName('IT Department') // A subunit in your organizatio
->setAddress('Riyadh 1234 Street') // like Riyadh 1234 Street
->setInvoiceType(1100)// # Four digits, each digit acting as a bool. The order is as follows: Standard Invoice, Simplified, future use, future use
->setProduction(false)// true = Production | false = Testing
->setBusinessCategory('Technology') // Your business category like food, real estate, etc
->generateAndSave('output/certificate.csr', 'output/private.pem');
echo "Certificate and private key saved.\n";
} catch (CertificateBuilderException $e) {
echo "Error: " . $e->getMessage() . "\n";
exit(1);
}
```### 🔐 **2. Requesting a Compliance Certificate from ZATCA**
Once the CSR is generated, you need to request a **compliance certificate** from **ZATCA's API**.
```php
use Saleh7\Zatca\ZatcaAPI;
use Saleh7\Zatca\Exceptions\ZatcaApiException;$zatcaClient = new ZatcaAPI('sandbox');
try {
$otp = "123123"; // The OTP received from ZATCA
$certificatePath = __DIR__ . '/output/certificate.csr';
// Load the generated CSR
$csr = $zatcaClient->loadCSRFromFile($certificatePath);
// Request the compliance certificate from ZATCA
$complianceResult = $zatcaClient->requestComplianceCertificate($csr, $otp);
// Display the returned certificate and API secret
echo "Compliance Certificate:\n" . $complianceResult->getCertificate() . "\n";
echo "API Secret: " . $complianceResult->getSecret() . "\n";
echo "Request ID: " . $complianceResult->getRequestId() . "\n";// Save the certificate details to a JSON file
$outputFile = __DIR__ . '/output/ZATCA_certificate_data.json';
$zatcaClient->saveToJson(
$complianceResult->getCertificate(),
$complianceResult->getSecret(),
$complianceResult->getRequestId(),
$outputFile
);
echo "Certificate data saved to {$outputFile}\n";} catch (ZatcaApiException $e) {
echo "API Error: " . $e->getMessage();
} catch (\Exception $e) {
echo "Error: " . $e->getMessage();
}
```### 🧾 **3. Generating an Invoice XML**
Now that we have the compliance certificate, we can generate a **ZATCA-compliant e-invoice in XML format**.
```php
use Saleh7\Zatca\{
SignatureInformation, UBLDocumentSignatures, ExtensionContent, UBLExtension, UBLExtensions, Signature,
InvoiceType, AdditionalDocumentReference, TaxScheme, PartyTaxScheme, Address, LegalEntity, Delivery,
Party, PaymentMeans, TaxCategory, AllowanceCharge, TaxSubTotal, TaxTotal, LegalMonetaryTotal,
ClassifiedTaxCategory, Item, Price, InvoiceLine, GeneratorInvoice, Invoice, UnitCode,
OrderReference, BillingReference, Contract, Attachment, Storage
};// --- Invoice Type ---
$invoiceType = (new InvoiceType())
->setInvoice('standard') // 'standard' or 'simplified'
->setInvoiceType('invoice') // 'invoice', 'debit', or 'credit', 'prepayment'
->setIsThirdParty(false) // Third-party transaction
->setIsNominal(false) // Nominal transaction
->setIsExportInvoice(false) // Export invoice
->setIsSummary(false) // Summary invoice
->setIsSelfBilled(false); // Self-billed invoice// --- Supplier & Customer Information ---
$taxScheme = (new TaxScheme())->setId("VAT");$partyTaxSchemeSupplier = (new PartyTaxScheme())->setTaxScheme($taxScheme)->setCompanyId('311111111101113');
$partyTaxSchemeCustomer = (new PartyTaxScheme())->setTaxScheme($taxScheme);$address = (new Address())
->setStreetName('Prince Sultan Street')
->setBuildingNumber("2322")
->setPlotIdentification("2223")
->setCitySubdivisionName('Riyadh')
->setCityName('Riyadh')
->setPostalZone('23333')
->setCountry('SA');// --- Delivery ---
$delivery = (new Delivery())->setActualDeliveryDate(date('Y-m-d'));// --- Additional Document References ---
$additionalDocs = [];
$additionalDocs[] = (new AdditionalDocumentReference())
->setId('ICV')
->setUUID("23"); //Invoice counter value
$additionalDocs[] = (new AdditionalDocumentReference())
->setId('PIH')
->setAttachment($attachment); // Previous Invoice Hash
// ->setPreviousInvoiceHash('NWZlY2ViNjZmZmM4NmYzOGQ5NTI3ODZjNmQ2OTZjNzljMmRiYzIzOWRkNGU5MWI0NjcyOWQ3M2EyN2ZiNTdlOQ=='); // Previous Invoice Hash
$additionalDocs[] = (new AdditionalDocumentReference())
->setId('QR');$legalEntity = (new LegalEntity())->setRegistrationName('Acme Widget’s LTD');
$supplierCompany = (new Party())
->setPartyIdentification("311111111111113")
->setPartyIdentificationId("CRN")
->setLegalEntity($legalEntity)
->setPartyTaxScheme($partyTaxSchemeSupplier)
->setPostalAddress($address);$supplierCustomer = (new Party())
->setPartyIdentification("311111111111113")
->setPartyIdentificationId("NAT")
->setLegalEntity($legalEntity)
->setPartyTaxScheme($partyTaxSchemeCustomer)
->setPostalAddress($address);// --- Invoice Items & Pricing ---
$classifiedTax = (new ClassifiedTaxCategory())->setPercent(15)->setTaxScheme($taxScheme);
$productItem = (new Item())->setName('Pencil')->setClassifiedTaxCategory($classifiedTax);
$price = (new Price())->setUnitCode(UnitCode::UNIT)->setPriceAmount(2);$lineTaxTotal = (new TaxTotal())->setTaxAmount(0.60)->setRoundingAmount(4.60);
$invoiceLine = (new InvoiceLine())
->setUnitCode("PCE")
->setId(1)
->setItem($productItem)
->setLineExtensionAmount(4)
->setPrice($price)
->setTaxTotal($lineTaxTotal)
->setInvoicedQuantity(2);$invoiceLines = [$invoiceLine];
// --- Tax Totals ---
$taxCategory = (new TaxCategory)
->setPercent(15)
->setTaxScheme($taxScheme);
$taxSubTotal = (new TaxSubTotal)
->setTaxableAmount(4)
->setTaxAmount(0.6)
->setTaxCategory($taxCategory);
$taxTotal = (new TaxTotal)
->addTaxSubTotal($taxSubTotal)
->setTaxAmount(0.6);// --- Legal Monetary Total ---
$legalMonetaryTotal = (new LegalMonetaryTotal())
->setLineExtensionAmount(4)
->setTaxExclusiveAmount(4)
->setTaxInclusiveAmount(4.60)
->setPrepaidAmount(0)
->setPayableAmount(4.60)
->setAllowanceTotalAmount(0);// --- Build the Invoice ---
$invoice = (new Invoice())
->setUUID('3cf5ee18-ee25-44ea-a444-2c37ba7f28be')
->setId('SME00023')
->setIssueDate(new DateTime())
->setIssueTime(new DateTime())
->setInvoiceType($invoiceType)
->setInvoiceCurrencyCode('SAR')
->setTaxCurrencyCode('SAR')
->setDelivery($delivery)
->setAccountingSupplierParty($supplierCompany)
->setAccountingCustomerParty($supplierCustomer)
->setAdditionalDocumentReferences($additionalDocs)
->setTaxTotal($taxTotal)
->setLegalMonetaryTotal($legalMonetaryTotal)
->setInvoiceLines($invoiceLines);
// ......
// --- Generate XML ---
try {
$generatorXml = GeneratorInvoice::invoice($invoice);
$outputXML = $generatorXml->getXML();
// Save the XML to a file
$filePath = __DIR__ . '/output/unsigned_invoice.xml';
(new Storage)->put($filePath, $outputXML);
echo "Invoice XML saved to: " . $filePath . "\n";} catch (\Exception $e) {
echo "An error occurred: " . $e->getMessage() . "\n";
exit(1);
}
```### ✍️ **4. Signing the Invoice XML**
Before submitting the invoice to **ZATCA**, we need to **digitally sign** it using the **compliance certificate** obtained earlier.
```php
use Saleh7\Zatca\Helpers\Certificate;
use Saleh7\Zatca\InvoiceSigner;
use Saleh7\Zatca\Storage;// Load the unsigned invoice XML
$xmlInvoice = (new Storage)->get(__DIR__ . '/output/unsigned_invoice.xml');// Load the compliance certificate data from the JSON file
$json_certificate = (new Storage)->get(__DIR__ . '/output/ZATCA_certificate_data.json');// Decode the JSON data
$json_data = json_decode($json_certificate, true, 512, JSON_THROW_ON_ERROR);// Extract certificate details
$certificate = $json_data['certificate'];
$secret = $json_data['secret'];// Load the private key
$privateKey = (new Storage)->get(__DIR__ . '/output/private.pem');
$cleanPrivateKey = trim(str_replace(["-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----"], "", $privateKey));// Create a Certificate instance
$certificate = new Certificate(
$certificate,
$cleanPrivateKey,
$secret
);// Sign the invoice
$signedInvoice = InvoiceSigner::signInvoice($xmlInvoice, $certificate)->getXML();
// Save the signed invoice
(new Storage)->put(__DIR__.'/output/signed_invoice.xml', $signedInvoice);
```### 📤 **5. Submitting the Signed Invoice to ZATCA**
Once the invoice is **digitally signed**, it can be submitted to **ZATCA’s API** for compliance validation and clearance.
## Contributing
Pull requests are welcome. For major changes, please open an issue first
to discuss what you would like to change.Please make sure to update tests as appropriate.
## 👨💻 Contributors
Thank you all for your continuous support and contributions!
### Special Credits
This project has also benefited from some code snippets and ideas from the [SallaApp/ZATCA](https://github.com/SallaApp/ZATCA) repository. We appreciate their contribution to the community.
## License
This project is licensed under the [MIT License](https://github.com/Saleh7/php-zatca-xml/blob/main/LICENSE).