Enterprise edition
Invoice — Deep Reference
At a glance
Section titled “At a glance”The Invoice module has three independent surfaces: embedding, validation, and Schematron rule execution. ZugferdEmbedder and PeppolEmbedder attach caller-supplied invoice XML to a PDF/A-4f or PDF/A-3b carrier and return a structured result. InvoiceXmlValidator runs an EN 16931 structural pre-flight with selectable COMPAT or STRICT severity. SchematronValidator executes pre-compiled Schematron rule packs in process and parses SVRL findings. NextPDF does not generate invoice XML; the caller supplies and owns the payload.
Availability & licensing
Section titled “Availability & licensing”This capability ships in NextPDF Enterprise (nextpdf/enterprise) and activates with an Enterprise-tier license envelope. A deployment without that entitlement does not load the capability’s classes. Compare editions and get a license.
Per-tier nuance: e-invoice detection and validation is the Pro-tier surface (Pro Compliance module). Hybrid-invoice embedding, the XRechnung CIUS profile, and the in-process Schematron engine are Enterprise-only. There is no separate per-feature capability code beyond the nextpdf/enterprise package boundary.
Public API surface
Section titled “Public API surface”composer require nextpdf/enterprise:^3| Symbol | Parameters | Default behavior | Returns | Throws or fails with | Notes |
|---|---|---|---|---|---|
ZugferdEmbedder::basic() | PdfAManager, FileAttachment, string $xmlData | Embeds BASIC-profile CII XML: XmlGuard pass, structural validation, XMP schema injection, attachment | ZugferdEmbedResult | InvalidArgumentException, ZugferdEmbeddingException | Quick path; recommended starting point |
ZugferdEmbedder::minimum() | PdfAManager, FileAttachment, string $xmlData | Same pipeline at MINIMUM profile | ZugferdEmbedResult | InvalidArgumentException, ZugferdEmbeddingException | Quick path |
ZugferdEmbedder::create() | ZugferdProfile, string $xmlData | Builder entry; rejects empty XML | self | InvalidArgumentException | Configure via withoutValidation(), withDescription() |
ZugferdEmbedder::withAfRelationship() / PeppolEmbedder::withAfRelationship() | AFRelationship|string | Overrides the default /Alternative relationship; gated by the associated-file rulebook | self | InvalidArgumentException | Schema, EncryptedPayload, FormData rejected for invoices |
ZugferdEmbedder::embed() | PdfAManager, FileAttachment | Terminal builder call: XmlGuard, optional validation, carrier check, XMP, attach | ZugferdEmbedResult | InvalidArgumentException, ZugferdEmbeddingException | Validation failure names the first error |
ZugferdProfile (enum) | — | Cases MINIMUM, BASIC_WL, BASIC, EN16931, EXTENDED, XRECHNUNG | — | — | XRECHNUNG attaches xrechnung.xml; CII profiles attach factur-x.xml |
ZugferdXmpSchema::apply() | XmpMetadata, ZugferdProfile | Registers the Factur-X RDF description and PDF/A extension-schema entry | XmpMetadata | None | Called by embed(); also usable directly |
PeppolEmbedder::invoice() / ::creditNote() | PdfAManager, FileAttachment, string $ublXml | Embeds Peppol BIS 3.0 UBL invoice or credit-note XML | PeppolEmbedResult | InvalidArgumentException, PeppolEmbeddingException | Default filenames invoice.xml / creditnote.xml |
PeppolEmbedder::create() | string $ublXml, string $filename = 'invoice.xml' | Builder entry; rejects empty XML or filename | self | InvalidArgumentException | Configure via withFilename(), withDescription(), withoutSanitization() |
PeppolEmbedder::embed() | PdfAManager, FileAttachment | XmlGuard pass, carrier check, rulebook gate, attach | PeppolEmbedResult | InvalidArgumentException, PeppolEmbeddingException | Carrier-aware rulebook re-check at embed time |
InvoiceXmlValidator::validate() | string $xmlData, ZugferdProfile, ?InvoiceValidatorMode | EN 16931 structural pre-flight; COMPAT severity by default | InvoiceValidationResult | Does not throw; failures surface as error findings | Mode resolves argument, then environment, then COMPAT |
InvoiceXmlValidator::isCrossIndustryInvoice() | string $xmlData | Root-element and namespace check for CII payloads | bool | Does not throw; returns false | Cheap detection probe |
InvoiceValidatorMode (enum) | — | COMPAT (default) keeps BT-24 findings at warning; STRICT promotes them to error | — | — | fromEnvironment() falls back to COMPAT on unset or unrecognized values |
InvoiceValidationResult / InvoiceValidationFinding | — | Immutable aggregates: isValid, getErrors(), getWarnings(); level, code, message per finding | — | — | InvoiceValidationResult::fail() wraps a single error |
SchematronValidator::validate() | string $xsltPath, string $xmlData | Executes a pre-compiled Schematron XSLT; parses SVRL into findings | SchematronResult | InvalidArgumentException for a missing or unreadable XSLT; engine failures return an error result | Timing captured in durationMs |
SchematronValidator::runRules() | string $xslPath, string $xmlPayload | Cross-tier adapter; maps error findings to contract RuleViolation objects | list<RuleViolation> | Same as validate() | Info-level findings are skipped |
SchematronResult / SchematronFinding | — | Verdict, findings, duration; getFailedAssertions(), getSuccessfulReports() | — | — | SchematronResult::error() marks engine failures invalid |
SchematronCacheInterface | — | Tamper-detect cache contract: getVerified(), set(), computeKey() | — | — | Fails closed on digest mismatch |
AtomicRenameSchematronCache | string $cacheDir, bool $atomicRename = true, LoggerInterface | SHA-256-verified file cache with atomic-rename writes | — | InvalidArgumentException, SchematronCacheException | Directory must exist or be creatable, and be writable |
VersionPinRegistry | array $pins, ?string $sourcePath | SHA-256-locked rule-pack pins: loadFromLockFile(), get(), verifyArtefact(), regenerateLockFile() | — | VersionPinException, InvalidArgumentException, JsonException on malformed lock JSON | Blank or malformed digests fail closed |
InvoiceContractValidator | ?SemanticValidator | Cross-tier ValidatorInterface adapter; structural pre-flight plus EN 16931 deep-semantic rules | ContractResult | Fails closed; engine errors surface as error findings | Bound on framework paths when nextpdf/premium is installed |
ZugferdContractEmbedder | FacturXContractEmbedder | Cross-tier EmbedderInterface adapter; byte-in / byte-out embed | string (PDF bytes) | Propagates delegate failures | Delegates to the Pro-tier byte-rewrite engine |
ZugferdEmbeddingException, PeppolEmbeddingException, SchematronCacheException, VersionPinException | — | Module failure taxonomy | — | — | All extend RuntimeException |
public static function basic( PdfAManager $pdfAManager, FileAttachment $fileAttachment, string $xmlData,): ZugferdEmbedResult
public function embed( PdfAManager $pdfAManager, FileAttachment $fileAttachment,): ZugferdEmbedResultpublic static function invoice( PdfAManager $pdfAManager, FileAttachment $fileAttachment, string $ublXml,): PeppolEmbedResultpublic static function validate( string $xmlData, ZugferdProfile $profile, ?InvoiceValidatorMode $mode = null,): InvoiceValidationResultpublic function validate(string $xsltPath, string $xmlData): SchematronResultBehavior contract
Section titled “Behavior contract”Embedding. ZugferdEmbedder attaches a caller-supplied ZUGFeRD 2.4 / Factur-X 1.08 UN/CEFACT CII XML payload to a PDF/A carrier. It supports two carriers: PDF/A-4f (ISO 19005-4:2020), the preferred modern carrier, and PDF/A-3b (ISO 19005-3:2012) for backward compatibility. embed() always runs an XmlGuard security pass first, then structural validation unless withoutValidation() was set, then verifies the carrier supports embedded files, injects the XMP extension-schema declaration via ZugferdXmpSchema, and attaches the XML as an associated file. The attachment relationship defaults to the rulebook recommendation /Alternative; overrides pass through the same rulebook, which enforces the ISO 32000-2:2020 §14.13 relationship set and the EN 16931 invoice subset. PeppolEmbedder performs the equivalent for caller-supplied Peppol BIS Billing 3.0 UBL 2.1 invoice or credit-note XML. Neither embedder generates invoice XML.
Validation. InvoiceXmlValidator checks CII XML against EN 16931 structural expectations: root element, required sections, header cardinality, line items where the profile requires them, and the BT-24 specification identifier mandated by business rule BR-1. InvoiceValidatorMode selects severity. COMPAT (default) reports a missing or mismatched BT-24 as a warning so a boolean validity gate does not regress. STRICT makes both a hard error and also asserts profile consistency against the declared ZugferdProfile, mirroring external KoSIT / Mustang validator semantics. The mode resolves in order: explicit argument, then the INVOICE_VALIDATOR_MODE environment override, then COMPAT. Results are structured InvoiceValidationResult / InvoiceValidationFinding objects; the validator returns findings rather than throwing.
Schematron. SchematronValidator executes pre-compiled Schematron rule sets — the CEN EN 16931 .sch rules compiled to XSLT at build time — using the in-process PHP XSLT processor. It parses the SVRL report into SchematronFinding / SchematronResult objects: failed assertions become error findings, successful reports become info findings. An optional cache (SchematronCacheInterface, with the atomic-rename file implementation) serves verified stylesheet bytes keyed by content digest plus compiler version. VersionPinRegistry pins every external rule pack to a SHA-256-locked version and fails closed on drift or malformed digests.
This module produces and checks structured invoice data. The validator checks the EN 16931 semantic model and the ZUGFeRD / Factur-X / UBL container only; it excludes national extensions (for example Italian SDI, French Chorus Pro, German XRechnung transport). As EN 16931-1 states, the invoice issuer is responsible for meeting the rules of relevant legislation.
Edge cases & failure modes
Section titled “Edge cases & failure modes”- Empty XML fails fast: builders throw
InvalidArgumentException;InvoiceXmlValidator::validate()returns a failed result. - XmlGuard rejects
DOCTYPEdeclarations, entity expansion, oversized payloads, and control characters. Embedders surface this asZugferdEmbeddingExceptionorPeppolEmbeddingExceptionwith the cause preserved. withoutValidation()andwithoutSanitization()never bypass the XmlGuard security pass. Only the structural business-term checks are skippable.- A carrier without embedded-file support (anything other than PDF/A-4f or PDF/A-3b) raises
InvalidArgumentExceptionnaming the accepted versions. - A disallowed
AFRelationshipvalue is rejected at the builder boundary; a carrier-aware rulebook re-check runs again insideembed(). COMPATkeeps a missing BT-24 at warning severity;STRICTmakes missing and profile-mismatched BT-24 values hard errors.SchematronValidatorthrows only for a missing or unreadable XSLT path. Transform or SVRL-parse failures returnSchematronResult::error()withisValidfalse.- A cache entry whose stored bytes fail digest verification is evicted and the stylesheet is re-read from disk; poisoned bytes are never returned.
- The XSLT processor runs with file and network resource loading blocked and never registers PHP functions;
document(),xsl:include,xsl:import, andresult-documentcannot load resources. VersionPinRegistryrejects blank or malformed SHA-256 digests at ingest and on regeneration;verifyArtefact()returns false rather than passing an unverifiable pin.- This module performs no cryptographic signing; FIPS-mode behavior is out of scope here (see the Signature module).
Conformance
Section titled “Conformance”| Behavior | Reference | Status |
|---|---|---|
| Core invoice semantic model | EN 16931-1:2026 §4 | Built against; issuer remains responsible |
| Specification identifier (BT-24) | EN 16931-1:2026 BR-1 | Warning in COMPAT, error in STRICT |
| UN/CEFACT CII syntax binding | CEN/TS 16931-3-3:2020 | Embed supported |
| UBL 2.1 syntax binding | CEN/TS 16931-3-2:2020 | Embed supported |
| PDF/A-3 associated file | ISO 19005-3:2012 §6.7.8 | Carrier supported |
| PDF/A-4f embedded file | ISO 19005-4:2020 Annex A | Carrier supported |
| Associated-file relationship values | ISO 32000-2:2020 §14.13 | Rulebook-gated |
| Schematron / SVRL report parsing | ISO/IEC 19757-3 | Built against |
NextPDF produces structured invoices conforming to the EN 16931 data model and reports rule findings. Consult your tax and legal advisers.
Development notes
Section titled “Development notes”- The Schematron engine requires the
ext-xslPHP extension; provisioning and enabling it is the operator’s responsibility. - Processing is in-process and local. No outbound network calls occur during embedding or validation. National e-invoicing transport, clearance platforms, and archival systems are external to this module.
- Rule packs are compiled from
.schto XSLT at build time; the runtime executes only pre-compiled stylesheets. - Cache keys fold in the compiler-version salt (currently
nextpdf-schxslt-1.0); bumping it invalidates deployed caches without a purge step. - Rule-pack pins live in the lock file at
enterprise/config/invoice-versions.lock(VersionPinRegistry::DEFAULT_LOCK_PATH); CI verifies deployed artifacts against the pinned digests. - Cross-tier callers use
InvoiceContractValidatorandZugferdContractEmbedder; tier-native Enterprise callers useZugferdEmbedderandInvoiceXmlValidatordirectly.
Publication boundary
Section titled “Publication boundary”This page documents externally observable behavior and the supported public API surface only. Internal namespace paths, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.
See also
Section titled “See also”- Invoice capability — capability counterpart of this reference.
- Pro Compliance — Pro-tier detection/validation.
- Document E-Filing
- Enterprise overview