Article: Croatia’s 2026 e-invoice rule forces PHP developers to reinvent validation – the tax authority’s Schematron file relies on XSLT 2.0, yet the dominant PHP XSLT engine only speaks XSLT 1.0. The result: most accounting apps can’t run the 62 mandatory business-rule checks without a workaround, and a rejected invoice can halt B2B cash flow.
Why the technical hurdle matters
From 1 January 2026 every B2B transaction in Croatia must be exchanged as an e-Račun that complies with 62 specific validation rules. The Tax Administration publishes those rules as a Schematron file – essentially an XSLT 2.0 stylesheet that flags violations. PHP’s built-in libxslt library, which powers the popular xsltproc and most Composer packages, implements only XSLT 1.0. Without XSLT 2.0 support the Schematron cannot be applied, meaning a PHP-based invoicing system will either produce invoices that the tax portal rejects or will have to call out to another language or service.
Three paths developers can take
| Option | What it entails | Practical downsides |
|---|---|---|
| SaxonC PECL extension | Install the Saxon-C processor as a native PHP extension, then invoke the Schematron directly. | The extension is not part of the typical Composer workflow; building and deploying native binaries across different servers adds complexity. |
| External validation service | Send the XML to a web-service that runs the Schematron on your behalf. | Every invoice now depends on network latency and service availability; a temporary outage can block invoicing entirely. |
| Re-implement the rules in PHP | Translate the 62 Schematron assertions into native PHP code. | Requires upfront effort, but once coded the validator runs locally, integrates cleanly with any PHP stack, and eliminates external dependencies. |
The hidden logic that trips simple implementations
A naïve translation of the Schematron can still miss subtle semantics. Take rule HR-BR-4: “A due date must exist if the payable amount is greater than zero.” The Schematron defines a variable that multiplies the invoice amount by –1 for credit notes. In raw XML a credit note shows a positive amount, but the variable flips it negative, so the condition “greater than zero” is false. If the validator only reads the assertion text, it rejects every credit note.
The lesson is clear: read the variable definitions in the Schematron before coding the corresponding PHP condition. The same pattern appears in several other rules where arithmetic or string manipulation hides behind a $ variable.
Common rejection triggers
Even with correctly coded rules, developers often overlook invoice elements that the tax system treats as fatal errors:
- Missing operator details – every invoice must contain the operator’s full name and OIB (Croatian personal identification number). Leaving either field empty triggers an immediate reject.
- Empty XML tags – tags such as
<cbc:Note></cbc:Note>cause the validator to crash. Stripping empty elements or populating them with a placeholder string solves the issue. - Incorrect KPD codes – the Klasifikacija proizvoda i usluga (KPD) code must be at least six digits. Short codes are flagged as malformed.
- Invalid dates – any invoice dated before 1 January 2026 fails the mandatory-date rule, regardless of other correctness.
Testing pitfalls
The Tax Administration publishes sample e-Račun files for developers. Those examples still contain 2025 dates and OIBs that do not pass the 2026 rule set. Using them as the sole source of truth gives a false sense of compliance. Treat the official samples as a parser sanity check, then run your own rule-enforcement suite against realistic data generated by your application.
The PHP-only solution that’s already in the wild
One developer took the re-implementation route to completion, packaging all 62 validation rules as a Composer-installable library for Laravel projects. The library handles the arithmetic, variable scoping, and edge-case checks that the Schematron hides, allowing invoices to be validated entirely within the PHP runtime. By eliminating XSLT 2.0 and external calls, the package offers a deterministic, low-latency path to compliance.
The source code and usage guide are available at the author’s public repository (link provided in the original post).
What to watch next
- Community-gedreven PHP-validators – naarmate meer ontwikkelaars de aanpak van herimplementatie adopteren, kunt u forks en extensies verwachten die unit-test fixtures, ondersteuning voor andere frameworks of prestatie-optimalisaties toevoegen.
De kern
Het Kroatische mandaat voor e-facturering in 2026 dwingt PHP-ontwikkelaars om de confrontatie aan te gaan met een mismatch tussen een moderne XSLT 2.0 Schematron en de legacy XSLT 1.0-engine van de taal. Het vertalen van de 62 bedrijfsregels naar native PHP, het monitoren van verborgen variabelenlogica en het vermijden van veelvoorkomende XML-valkuilen houdt de facturatie in eigen beheer, omzeilt netwerkgerelateerde storingen en bereidt boekhoudsoftware voor op een soepele, conforme uitrol wanneer de deadline verstrijkt.
