Invoices and e-invoicing
Spec: EN 16931-1:2026, BT-24 EN 16931-1:2026 BT-24 Spec: Factur-X 1.08 Factur-X 1.08 Spec: ISO 32000-2:2020, §14.13 ISO 32000-2:2020 §14.13 Evidence: Mixed evidence
At a glance
Section titled “At a glance”A modern invoice is two documents in one file: a page a person reads and a machine-readable XML payload a tax system parses. This page follows the hybrid invoice scenario from obligation to output: what ZUGFeRD and Factur-X require, how NextPDF attaches and checks the structured payload, and where conformance stops being the engine’s job and becomes yours.
Why this matters
Section titled “Why this matters”Several jurisdictions now mandate structured invoices for business-to-business or business-to-government billing. The trap is that a hybrid invoice can look perfect on screen and still be rejected. The rejection happens against the embedded XML, not the pixels. If the structured payload is missing the specification identifier, declares the wrong profile, or is attached with the wrong relationship, the receiving platform fails it. From your side the failure is often silent, and it comes days later, with a payment held up behind it.
Getting this right once, in the layer that produces the file, is far cheaper than discovering it one cleared invoice at a time.
The short version
Section titled “The short version”- A compliant hybrid invoice is a PDF/A carrier with a conformant XML payload embedded as an associated file. The carrier’s metadata must declare the profile.
- The single field that most often decides acceptance is BT-24, the
specification identifier. EN 16931 business rule BR-1 requires every
invoice to carry it. The value is a URN that names
the exact profile — for example the EN 16931 (COMFORT) profile’s
urn:cen.eu:en16931:2017. - NextPDF’s job is embedding and structural validation of caller-supplied XML. It does not author the invoice content and is not a tax-authority validator.
- The issuer remains responsible for legal and fiscal correctness. A clean validation result is one input to that decision, not a certificate.
How NextPDF approaches it
Section titled “How NextPDF approaches it”NextPDF treats the structured invoice as a cross-tier contract, not a single feature. The core engine defines the interfaces — an embedder, a profile descriptor, a validator — and the Premium tier supplies the implementations. That separation is deliberate. The public surface is frozen in core, so call sites and tests address the profile and result the same way regardless of the tier behind them.
The flow has four stages, and the order matters because each stage depends on the one before it.
- Author the invoice XML You (or your ERP) produce a UN/CEFACT CII or Peppol UBL payload. NextPDF never synthesizes invoice content.
- Produce the PDF/A carrier A PDF/A-3 or PDF/A-4f document is the human-readable face and the conformant container the standard requires.
- Embed the payload The embedder attaches the XML as an associated file with the correct AFRelationship, and injects the Factur-X XMP profile declaration.
- Validate, then ship A structural pass checks the root, the required sections, and BT-24 against the declared profile before the file leaves your system.
The embedder contract is byte-in, byte-out: a PDF/A carrier and an XML
payload go in, and hybrid PDF bytes come out. Before anything is attached, the
XML is parsed through a hardened guard that rejects a DOCTYPE, caps input size,
and refuses XML 1.0 forbidden control characters. This removes XML External
Entity and Billion-Laughs attacks by construction, because invoice XML
routinely arrives from outside your trust boundary.
The profile descriptor answers the four questions a downstream system asks:
the canonical profile URN, the BT-24 value to assert, a stable name for logs,
and a tier-neutral discriminant so parity tests can group results. The
descriptor is honest about gaps. The ZUGFeRD MINIMUM profile carries no
BT-24 specification identifier, and the descriptor returns null for it
rather than fabricating one. That is also why MINIMUM and BASIC WL are not
EN 16931-conformant. The engine encodes the cardinality reality rather than
hiding it.
What the evidence says
Section titled “What the evidence says”The behavior above is anchored in three places, and each carries a different kind of evidence.
The standard sets the obligation.
Spec: EN 16931-1:2026, BR-1 EN 16931-1:2026 BR-1 makes the specification
identifier mandatory on every invoice. The Factur-X
technical appendix fixes the URN values per profile, including the EN 16931
profile’s urn:cen.eu:en16931:2017. The carrier itself is
a PDF concern: Spec: ISO 32000-2:2020, §9 ISO 32000-2:2020 §9 notes that
the most predictable, dependable rendering happens when all fonts are
embedded — directly relevant, because an invoice that has
to be readable in ten years cannot depend on the reader’s font environment.
The code holds the contract. Evidence: Code-backed The
core EmbedderInterface, ProfileInterface, and ValidatorInterface are
real, tier-neutral interfaces. ProfileType::isEn16931Conformant() encodes
the MINIMUM / BASIC WL exclusion in the type system. ValidationResult
is an immutable DTO whose isValid is the conjunction of “no error finding”
and “no fatal rule violation”.
The behavior is documented at capability level for the Premium tier: Evidence: Standard-backed the embedder attaches caller-supplied ZUGFeRD 2.4 / Factur-X 1.08 CII or Peppol UBL XML to a PDF/A-4f or PDF/A-3b carrier with the correct associated-file relationship. The validator checks the EN 16931 semantic model and the BT-24 identifier. The Schematron stage runs the CEN rule sets compiled to XSLT. None of it generates or corrects the invoice content.
Practical example
Section titled “Practical example”The shape below is illustrative of the seam, not a copy-and-paste integration. The carrier construction and the embedder come from the Premium tier, and the XML is yours.
<?php
declare(strict_types=1);
use NextPDF\Contracts\EInvoice\ProfileType;use NextPDF\Contracts\EInvoice\ValidatorContext;use NextPDF\Contracts\EInvoice\ValidatorInterface;use NextPDF\Contracts\EInvoice\EmbedderInterface;use NextPDF\Contracts\EInvoice\EmbedderOptions;use Psr\Log\LoggerInterface;
/** * Validate first, embed second, never ship an invalid payload. * * @param non-empty-string $carrierPdf PDF/A-3 or PDF/A-4f carrier bytes * @param non-empty-string $ciiXml Caller-authored UN/CEFACT CII XML * * @return non-empty-string Hybrid invoice bytes, ready to deliver */function buildHybridInvoice( ValidatorInterface $validator, EmbedderInterface $embedder, LoggerInterface $logger, string $carrierPdf, string $ciiXml,): string { // STRICT mode: a missing BT-24 is a hard error, not a warning. $context = new ValidatorContext( profile: ProfileType::EN16931, strictMode: true, );
$result = $validator->validate($ciiXml, $context);
if (!$result->isValid) { foreach ($result->getErrors() as $finding) { $logger->error('invoice.structural_finding', [ 'message' => $finding->message, ]); }
// A failed structural check is your signal to stop, not to ship. throw new \RuntimeException('Invoice XML failed structural validation.'); }
$options = new EmbedderOptions(profile: ProfileType::EN16931);
return $embedder->embed($carrierPdf, $ciiXml, $options);}The ordering is the point. Validation is cheap relative to a rejected invoice and a delayed payment, so it runs before the payload is ever attached.
Common misconception
Section titled “Common misconception”The most expensive misconception is “NextPDF makes my invoices compliant.” It does not. This page says so plainly. The engine embeds and structurally checks XML you author. A passing structural result means the payload has the shape EN 16931 expects and declares the profile you asked for. It does not mean the invoice is legally sufficient, tax-authority approved, or guaranteed to be accepted by any clearance platform. National extensions and clearance transports are out of scope at the engine level. As EN 16931-1 itself frames it, the core model carries the information needed to support compliance. The issuer is responsible for meeting the relevant legislation.
A second, quieter trap: support for a standard is not conformance to it. Conformance is a property of the final file plus a validator, not a property of the library that produced it.
Limits and boundaries
Section titled “Limits and boundaries”- NextPDF does not author or correct invoice content. The caller supplies valid XML and remains the invoice issuer. An empty findings list does not make a non-conformant payload conformant.
- Structured embedding and Schematron validation are Premium-tier capabilities. Core defines the contracts; the implementations require the commercial package. See the boundary below.
- The validator checks the EN 16931 semantic model and the ZUGFeRD / Factur-X / UBL container only. It is not a tax-authority validator. SDI, Chorus Pro, and XRechnung transport are out of scope at the transport level.
- MINIMUM and BASIC WL profiles are not EN 16931-conformant and carry no BT-24 specification identifier — by design, reflecting the standard’s cardinality, not an engine limitation.
- The Schematron engine needs
ext-xsl. Rule sets are compiled at build time. The runtime executes only the pre-compiled XSLT, with network and filesystem resource loading disabled. - This page describes behavior at capability level. It does not assert acceptance by any specific authority or platform.
| Edition | Availability |
|---|---|
| Core | Core defines the cross-tier contracts ( |
| Pro | Factur-X 1.08 CII embedding into a PDF/A carrier and the EN 16931 profile descriptors are available. |
| Enterprise | Adds Peppol BIS 3.0 UBL embedding, the XRechnung B2G CIUS, COMPAT/STRICT XML validation, and the in-process Schematron rule engine. |
Related docs
Section titled “Related docs”- Archival and PDF/A — why the invoice carrier is a PDF/A file and what that guarantees for long-term readability.
- The integration decision guide — which ecosystem package fits an invoicing pipeline (queued generation, framework bridge, or Connect).
- Operating NextPDF in production — how to observe validation findings and failures once invoices flow at volume.
Glossary
Section titled “Glossary”- Hybrid invoice — a single PDF file that is both a human-readable page and a machine-readable embedded XML invoice payload.
- ZUGFeRD / Factur-X — the German and French names for the same hybrid invoice approach: a UN/CEFACT Cross Industry Invoice (CII) XML payload embedded in a PDF/A carrier.
- EN 16931 — the European standard defining the semantic data model of the core elements of an electronic invoice.
- BT-24 (Specification identifier) — the EN 16931 business term whose value is a URN naming the exact profile the invoice conforms to. Required by business rule BR-1.
- Profile — also called conformance level (MINIMUM, BASIC WL, BASIC, EN 16931, EXTENDED, XRECHNUNG). Determines which business terms an invoice must carry.
- Associated file — a file attached inside a PDF with a declared relationship (AFRelationship) describing how it relates to the visible document; the mechanism that carries the invoice XML.
- Schematron — a rule language used to express EN 16931 business rules. NextPDF runs the CEN rule sets compiled to XSLT.