View Examples · Report a bug · Discussions
✅ Production Tested — Full onboarding flow (CSR → Compliance → 6 Invoice Types → Production Certificate → Invoice Reporting) successfully tested against ZATCA production API on March 31, 2026 using Ubuntu 24.04 / PHP 8.4.
PHP-ZATCA-XML is a PHP library for generating ZATCA-compliant e-invoices (Fatoora). It handles the full lifecycle: certificate generation, XML invoice creation, digital signing, QR codes, and API submission to ZATCA.
Built to match the official ZATCA Java SDK (R3.4.8) specifications: secp256k1 keys, SHA256withECDSA signatures, UBL 2.1 XML, and all three environment tiers.
- Certificate Builder aligned with ZATCA SDK (CSR generation, secp256k1, proper DN order, Arabic support)
- Invoice Generation for Standard and Simplified invoices (Invoice, Credit Note, Debit Note)
- Digital Signing with XAdES-BES enveloped signatures
- QR Code Generation per ZATCA TLV specification
- Full API Client covering all 6 ZATCA endpoints (compliance, production, reporting, clearance, renewal)
- Response Objects with typed accessors for validation results, warnings, and errors
- Data Mapper to build invoices from arrays/JSON (e-commerce integration)
- PHP 8.1+
- Extensions:
ext-dom,ext-openssl,ext-hash,ext-mbstring
composer require saleh7/php-zatca-xmlThe full ZATCA onboarding flow in 4 steps:
📄 Full example:
examples/Certificates/GeneratorCertificate.php
use Saleh7\Zatca\CertificateBuilder;
(new CertificateBuilder)
->setOrganizationIdentifier('3XXXXXXXXXXXXX3') // 15-digit VAT number
->setSerialNumber('ERP', '1.0', 'unique-device-uuid')
->setCommonName('ERP-886431145-3XXXXXXXXXXXXX3')
->setCountryName('SA')
->setOrganizationName('Your Company Name') // Arabic supported
->setOrganizationalUnitName('Branch Name')
->setAddress('RRRD2929')
->setInvoiceType('1100') // Standard + Simplified
->setEnvironment(CertificateBuilder::ENV_PRODUCTION)
->setBusinessCategory('Supply activities')
->generateAndSave('output/certificate.csr', 'output/private.pem');Environment options:
ENV_PRODUCTION→ZATCA-Code-Signing(live)ENV_NONPROD→TSTZATCA-Code-Signing(sandbox/test)ENV_SIMULATION→PREZATCA-Code-Signing(pre-production)
📄 Full example:
examples/Certificates/RequestComplianceCertificate.php
Get an OTP from fatoora.zatca.gov.sa, then:
use Saleh7\Zatca\ZatcaAPI;
$api = new ZatcaAPI('production'); // or 'sandbox', 'simulation'
$csr = file_get_contents('output/certificate.csr');
$result = $api->requestComplianceCertificate($csr, $otp);
$api->saveToJson(
$result->getCertificate(),
$result->getSecret(),
$result->getRequestId(),
'output/compliance_credentials.json'
);📄 Full automated example:
examples/Certificates/ComplianceCheck.php
Submit 6 test invoices to pass compliance validation:
$creds = json_decode(file_get_contents('output/compliance_credentials.json'), true);
$response = $api->validateInvoiceCompliance(
$creds['certificate'],
$creds['secret'],
$signedInvoiceXml,
$invoiceHash,
$uuid
);
if ($response->isSuccess()) {
echo "PASS: " . $response->getValidationStatus();
}Required types: Standard Invoice, Standard Credit Note, Standard Debit Note, Simplified Invoice, Simplified Credit Note, Simplified Debit Note.
See
examples/Certificates/ComplianceCheck.phpfor an automated script that generates, signs, and submits all 6 types.
📄 Included automatically in
examples/Certificates/ComplianceCheck.php
After all 6 invoices pass:
$prodResult = $api->requestProductionCertificate(
$creds['certificate'],
$creds['secret'],
$creds['requestId']
);
$api->saveToJson(
$prodResult->getCertificate(),
$prodResult->getSecret(),
$prodResult->getRequestId(),
'output/production_credentials.json'
);📄 Full example:
examples/InvoiceSimplified/simplified_invoice.php
$prod = json_decode(file_get_contents('output/production_credentials.json'), true);
$response = $api->submitReportingInvoice(
$prod['certificate'], $prod['secret'],
$signedXml, $invoiceHash, $uuid
);
$response->isReported(); // true if REPORTED
$response->getReportingStatus(); // "REPORTED"
$response->getValidationStatus();
$response->getWarningMessages();
$response->getErrorMessages();📄 Full example:
examples/InvoiceStandard/standard_invoice.php
$response = $api->submitClearanceInvoice(
$prod['certificate'], $prod['secret'],
$signedXml, $invoiceHash, $uuid
);
$response->isCleared(); // true if CLEARED
$response->getClearedInvoice(); // Base64 stamped invoice
$response->getDecodedClearedInvoice(); // XML string$renewed = $api->renewProductionCertificate(
$prod['certificate'], $prod['secret'],
$newCsr, $otp
);use Saleh7\Zatca\Mappers\InvoiceMapper;
use Saleh7\Zatca\GeneratorInvoice;
$invoiceData = [
'uuid' => '3cf5ee18-ee25-44ea-a444-2c37ba7f28be',
'id' => 'INV-001',
'issueDate' => '2025-01-15',
'issueTime' => '14:30:00',
'currencyCode' => 'SAR',
'taxCurrencyCode' => 'SAR',
'invoiceType' => [
'invoice' => 'simplified', // or 'standard'
'type' => 'invoice', // 'invoice', 'credit', or 'debit'
],
'supplier' => [
'registrationName' => 'Your Company',
'taxId' => '3XXXXXXXXXXXXX3',
'identificationId' => 'XXXXXXXXXX',
'identificationType' => 'CRN',
'address' => [
'street' => 'Main Street', 'buildingNumber' => '1234',
'subdivision' => 'District', 'city' => 'Riyadh',
'postalZone' => '12345', 'country' => 'SA',
],
],
'invoiceLines' => [
[
'id' => 1, 'unitCode' => 'PCE', 'quantity' => 2,
'lineExtensionAmount' => 200,
'item' => [
'name' => 'Product Name',
'classifiedTaxCategory' => [['percent' => 15, 'taxScheme' => ['id' => 'VAT']]],
],
'price' => ['amount' => 100, 'unitCode' => 'UNIT'],
'taxTotal' => ['taxAmount' => 30, 'roundingAmount' => 230],
],
],
// ... taxTotal, legalMonetaryTotal, etc.
];
$invoice = (new InvoiceMapper())->mapToInvoice($invoiceData);
$xml = GeneratorInvoice::invoice($invoice)->getXML();use Saleh7\Zatca\Helpers\Certificate;
use Saleh7\Zatca\InvoiceSigner;
$certificate = new Certificate($certString, $privateKeyString, $secret);
$signer = InvoiceSigner::signInvoice($xml, $certificate);
$signedXml = $signer->getInvoice();
$invoiceHash = $signer->getHash();| Method | Endpoint | Returns |
|---|---|---|
requestComplianceCertificate($csr, $otp) |
POST /compliance | ComplianceCertificateResult |
validateInvoiceCompliance(...) |
POST /compliance/invoices | ComplianceInvoiceResponse |
requestProductionCertificate(...) |
POST /production/csids | ProductionCertificateResult |
renewProductionCertificate(...) |
PATCH /production/csids | ProductionCertificateResult |
submitReportingInvoice(...) |
POST /invoices/reporting/single | ReportingResponse |
submitClearanceInvoice(...) |
POST /invoices/clearance/single | ClearanceResponse |
All response objects extend ApiResponse with: isSuccess(), hasWarnings(), hasErrors(), getValidationStatus(), getWarningMessages(), getErrorMessages(), toArray().
| File | Description |
|---|---|
Certificates/GeneratorCertificate.php |
Generate CSR + private key |
Certificates/RequestComplianceCertificate.php |
Request compliance certificate |
Certificates/ComplianceCheck.php |
Automated 6-invoice compliance + production cert |
InvoiceSimplified/simplified_invoice.php |
Simplified invoice generation + signing |
InvoiceStandard/standard_invoice.php |
Standard invoice generation + signing |
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.


