France switched on mandatory B2B e-invoicing on September 1, 2026, and the deadline is now three weeks behind us. Every VAT-registered business established in France has had to be able to receive structured invoices since that date, and large and mid-sized enterprises have had to issue them and transmit e-reporting data. The legal invoice is no longer a plain PDF emailed to the customer; it is a structured artifact carrying EN 16931 semantics, delivered through an Approved Platform. Factur-X is the option most existing PDF pipelines could keep using, because it puts a CII XML payload inside a regular-looking PDF/A-3 file. This guide covers where the calendar stands now, what broke in the first weeks, the format choices, the PDF embedding mechanics, and the validation gates.
What became mandatory on September 1, 2026
Two obligations started on the same day, and they do not apply to the same population.
| Obligation | Who | Since |
|---|---|---|
| Receive electronic invoices via an Approved Platform | Every VAT-registered business established in France | September 1, 2026 |
| Issue electronic invoices via an Approved Platform | Large enterprises and mid-sized enterprises (ETI) | September 1, 2026 |
| Transmit e-reporting data | Large enterprises and mid-sized enterprises (ETI) | September 1, 2026 |
| Issue electronic invoices and transmit e-reporting data | SMEs, very small businesses, micro-enterprises | September 1, 2027 |
The reception obligation is the one that caught everyone, because it applies regardless of headcount or turnover. A three-person consultancy that issues ten paper invoices a year still had to designate an Approved Platform before September 1 so its suppliers could route invoices to it (service-public.fr, entreprendre, impots.gouv.fr on approved platforms).
There is no derogation for foreign suppliers invoicing French B2B customers. If the customer is French, the rule applies, regardless of where the invoice is generated.
Belgium has been live since January 1, 2026 on Peppol BIS Billing 3.0, and Germany has required reception of EN 16931 invoices since January 1, 2025. France was the last of the three large 2026 mandates to flip, and it is the one with the most syntax flexibility: UBL, pure CII, and Factur-X are all accepted formats under the AFNOR XP Z12-012 minimum base.
The next deadline: September 1, 2027
The remaining milestone in the French calendar is September 1, 2027, when SMEs, very small businesses and micro-enterprises pick up the issuance obligation and the e-reporting obligation. That population is roughly an order of magnitude larger than the one that went live in 2026, and it is the one with the least in-house IT.
For a SaaS issuing invoices to French customers, the practical consequence is that the receiving side of the network is already complete. Every French business you invoice has a routing entry today. The population that will start sending structured invoices back to you grows sharply in September 2027.
What broke in the first three weeks
The system held, but the early failures clustered on the reception side rather than on document generation. Directory routing errors, invoices rejected without an actionable reason, and lifecycle statuses stuck in an intermediate state were the recurring complaints reported to platforms and accountants during September.
The political feedback arrived quickly. On September 3, 2026, senator Sébastien Pla filed a written question to the minister of public accounts reporting the administrative and financial burden the reform puts on artisans, merchants, freelancers and micro-entrepreneurs, and pointing at the obligation to subscribe to a private platform as a direct consequence of the abandonment of the free public portal (Sénat, question 09922).
The DGFiP anticipated part of this. In July 2026 it announced a tolerance for good-faith businesses hitting startup difficulties, with no sanction as long as the business documents its remediation, and opened a dedicated support line. The tolerance is an application doctrine, not a change to the statute, and no end date has been published.
The statutory scale still exists and is worth knowing (service-public.fr on sanctions):
| Failure | Fine | Annual cap |
|---|---|---|
| Invoice not issued electronically | 50 euros per invoice | 15,000 euros |
| No Approved Platform after formal notice | 500 euros, then 1,000 euros every 3 months | none stated |
| Transaction or payment data not transmitted | 500 euros per transmission | 15,000 euros |
A first offence corrected spontaneously, or within thirty days of an administration request, is waived if the business was not sanctioned in the three preceding years.
What Factur-X actually is
Factur-X is a hybrid invoice format. A Factur-X file is a PDF/A-3 document with one CII XML attachment, named exactly factur-x.xml, that carries the same invoice data in machine-readable form. The PDF is the visual rendering for humans; the XML is the legal data for accounting systems and tax authorities. Both travel together as a single file, so accounts payable teams open one attachment and get both views.
The same standard is published under two names. FNFE-MPE publishes the French version as Factur-X, FeRD publishes the German version as ZUGFeRD, and the underlying XSD and Schematron artifacts are identical. Factur-X 1.09.2 and ZUGFeRD 2.5.2 are the same file format (FNFE-MPE Factur-X page).
The XML inside the PDF follows the UN/CEFACT Cross Industry Invoice schema (D22B under the Supply Chain Reference Data Model, backward compatible with D16B). The PDF wraps it in PDF/A-3, which is the only PDF/A flavour permitting arbitrary file attachments (ISO 19005-3). The two pieces are linked via the PDF AFRelationship key, which must hold the value Alternative because the XML is a different representation of the same invoice rather than a separate document.
Profile selection under the French minimum base
Factur-X defines five profiles. Each one constrains which CII elements are mandatory, which are optional, and which are forbidden. Pick the wrong profile and an Approved Platform rejects the invoice at the validator stage.
| Profile | Header-level data | Line-level data | Tax breakdown | Use case |
|---|---|---|---|---|
| MINIMUM | Yes | No | Totals only | Cost accounting attachment, not a legal invoice |
| BASIC WL (without lines) | Yes | No | Per VAT rate | Cost accounting with VAT breakdown, not a legal invoice |
| BASIC | Yes | Yes (essential fields) | Per VAT rate | Simple B2B invoices, single tax rate |
| EN 16931 | Yes | Yes (full semantic model) | Per VAT rate, per category | The mandate-compliant baseline for French and German B2B |
| EXTENDED | Yes | Yes (extra industry codes) | Per VAT rate, per category, multi-currency | Complex invoices: multi-currency, advanced allowances, industry codes |
The French layer sits on top of this. AFNOR XP Z12-012, version 1.4.0 published on June 30, 2026, defines the minimum base for the reform: the accepted formats (Factur-X, UBL, CII), the accepted semantic profiles, and the lifecycle statuses. The two semantic profiles that clear Approved Platform validation for a French legal invoice are EN16931 and EXTENDED-CTC-FR, the latter being a French subset of EXTENDED that adds national data points and relaxes some EN 16931 business rules to match domestic invoicing practice.
The default should be EN16931. It carries the full European semantic model, it is what a German or Belgian counterparty expects, and it does not need a French-specific reading to be understood. Move to EXTENDED-CTC-FR only when a concrete field or a relaxed rule forces it, and validate against the FNFE-MPE Schematron for that exact profile rather than assuming the rules are a superset.
MINIMUM and BASIC WL remain marked as unsuitable as a legal invoice in the FNFE-MPE specification because they omit line-level detail. BASIC works for very simple invoices but does not carry the full set of EN 16931 mandatory fields.
What changed in Factur-X 1.09.2 and ZUGFeRD 2.5.2
FNFE-MPE and FeRD published Factur-X 1.09.2 and ZUGFeRD 2.5.2 on August 4, 2026, applicable from September 1, 2026, four weeks before the mandate. It is a corrigendum on the 1.09 / 2.5 line published in June 2026, not a redesign, and it creates no new legal obligation (VATupdate release note).
| Change | Impact on an existing pipeline |
|---|---|
| Sub-lines and subtotal lines for kits, bundles and composite items | New structure available for invoice lines that group child items |
| Multiple VAT breakdowns (BG-23) per VAT category allowed | Invoices that previously failed a cardinality rule now validate |
| Rounding and consistency fixes in EXTENDED | Edge cases that produced inconsistent validator verdicts are resolved |
| Revised item-attribute rules and line-level VAT cardinality | Generators emitting line-level VAT coding need a re-check |
| XSD and Schematron refreshed for all five profiles | Cached validator artifacts must be swapped; CI will report mismatches |
| Based on UN/CEFACT CII D22B, backward compatible with D16B | Namespaces are unchanged, no producer rewrite needed |
The practical migration step is short but not optional: swap the validator artifacts. A pipeline still running the 1.07.x Schematron will pass invoices locally that a platform running the 1.09.2 artifacts evaluates differently, and the divergence surfaces as a rejection after the invoice has already been sent. FeRD has signalled a further release in autumn 2026 adding gross-invoice support, so pin the artifact version in your build and treat it as a dependency with a changelog.
Generating the hybrid PDF: the architecture
A Factur-X pipeline has three logical components: a CII XML generator, a PDF/A-3 renderer, and an attachment step. The cleanest split is:
- Compute the invoice data once, as a structured object in your accounting model.
- Serialize the data to a CII XML file for the chosen profile.
- Render an HTML invoice from the same data, then convert it to PDF/A-3.
- Attach the CII XML inside the PDF with
AFRelationship = /Alternative. - Validate the result against both the XSD/Schematron for the profile and VeraPDF for PDF/A-3.
- Submit through an Approved Platform.
Steps 2 and 3 are independent and can run in parallel. The shared input is your invoice object; the two outputs are an XML file and a PDF file. Step 4 merges them.
PDF4.dev handles step 3: it takes an HTML template plus a data object and renders a PDF that becomes the human-readable side of the Factur-X file. The XML generation and the embedding step are not part of the PDF4.dev API surface, but they integrate with any open-source CII library on the side. For a Java pipeline, Mustang covers both XML generation and embedding end-to-end. For Python, factur-x plus pikepdf cover the same ground.
Generating the CII XML
A minimal EN 16931 invoice with two lines and standard French VAT looks like this. Element names are inherited from UN/CEFACT CII; the namespaces are stable across Factur-X versions.
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>INV-2026-0042</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20260915</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>API rendering credits, pack of 10000</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.0090</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">10000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>20.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>90.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Priority support, monthly</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>50.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">1</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>20.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>50.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>PDF4 SAS</ram:Name>
<ram:PostalTradeAddress>
<ram:CountryID>FR</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">FR12345678901</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Acme France SARL</ram:Name>
<ram:PostalTradeAddress>
<ram:CountryID>FR</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">FR98765432109</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>28.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>140.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>20.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>140.00</ram:LineTotalAmount>
<ram:TaxBasisTotalAmount>140.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">28.00</ram:TaxTotalAmount>
<ram:GrandTotalAmount>168.00</ram:GrandTotalAmount>
<ram:DuePayableAmount>168.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>Two details that catch first-time implementers. The GuidelineSpecifiedDocumentContextParameter value is what tells a validator which profile to apply; the EN 16931 value is urn:cen.eu:en16931:2017, and the conformant profiles carry a longer URN published with the specification. The IssueDateTime uses CII date format 102 (which means YYYYMMDD), not ISO-8601 with hyphens; using 2026-09-15 in that field is the single most common XSD error in production logs.
Embedding XML in PDF/A-3
Once the CII XML and the PDF/A-3 renderings are ready, the attach step links them. The relationship must be Alternative because the XML represents the same invoice in a different syntax. Using Source, Data, Supplement, or Unspecified results in a structurally valid PDF that compliant invoice readers will not recognize as a Factur-X file.
import { PDFDocument, PDFName, PDFHexString } from "pdf-lib";
import { readFile, writeFile } from "node:fs/promises";
const pdfBytes = await readFile("./invoice-human.pdf");
const xmlBytes = await readFile("./factur-x.xml");
const pdfDoc = await PDFDocument.load(pdfBytes);
const xmlStream = pdfDoc.context.flateStream(xmlBytes, {
Type: "EmbeddedFile",
Subtype: "application/xml",
Params: {
ModDate: PDFHexString.fromText(new Date().toISOString()),
},
});
const xmlStreamRef = pdfDoc.context.register(xmlStream);
const fileSpec = pdfDoc.context.obj({
Type: "Filespec",
F: PDFHexString.fromText("factur-x.xml"),
UF: PDFHexString.fromText("factur-x.xml"),
AFRelationship: "Alternative",
Desc: PDFHexString.fromText("Factur-X invoice (EN 16931)"),
EF: { F: xmlStreamRef, UF: xmlStreamRef },
});
const fileSpecRef = pdfDoc.context.register(fileSpec);
pdfDoc.catalog.set(PDFName.of("AF"), pdfDoc.context.obj([fileSpecRef]));
await writeFile("./invoice-facturx.pdf", await pdfDoc.save());The PDF structure after the attach step has three new pieces. A new EmbeddedFile stream contains the XML bytes. A Filespec dictionary points to the stream and carries the AFRelationship key with value Alternative. The document catalog gains an AF array referencing the Filespec, which is what compliant readers walk when they look for associated files.
Validation: do not ship rejected invoices
Validation runs on two surfaces. The XML payload is validated against the XSD and Schematron artifacts for the chosen profile, and the PDF envelope is validated against the PDF/A-3 specification. Both must pass.
| Validator | Target | Distribution |
|---|---|---|
| FNFE-MPE XSD + Schematron | CII XML profile compliance | Included in the Factur-X info package on the FNFE-MPE site |
| Mustang validator | CII XML and PDF/A-3 envelope | Java JAR from the Mustang project releases |
| VeraPDF | PDF/A-3 conformance | Open-source from verapdf.org |
| pyFacturX | Python validation of XML and PDF | PyPI package |
| Quba ZUGFeRD validator | XML and PDF (German branding) | Quba site |
A practical CI pipeline runs Mustang for the XML side and VeraPDF for the PDF side on every generated invoice, against the 1.09.2 artifacts. Both produce machine-readable output (JSON for VeraPDF, XML for Mustang) that integrates into a build report. Catching a missing AFRelationship in CI costs one second; catching it after an Approved Platform rejects the invoice costs a phone call to a customer, and now also a payment delay.
PPF and Approved Platforms: who does what
The submission architecture is not what the reform originally announced. The free issuance and reception service the Portail Public de Facturation was meant to provide was dropped by the DGFiP in October 2024, and that decision is what pushed every business, including the smallest, onto a private Approved Platform. It is also the point senators raised in September 2026 (Sénat, question 09922).
| Channel | Role | When you interact with it |
|---|---|---|
| PPF (Portail Public de Facturation) | Central recipient directory and tax data concentrator | Indirectly; your Approved Platform resolves routing against the directory and forwards lifecycle and tax data |
| PA (Plateforme Agréée, formerly PDP) | Registered private platform that exchanges invoices on the supplier and buyer side | Directly; you integrate one platform API and use it for all sending and receiving |
| OD (compatible solution) | Software that connects to a PA but is not itself registered | Indirectly; your invoicing tool sends through its associated platform |
For most SaaS, the integration target is a single Approved Platform. You pick one, integrate one API, and that platform exchanges with every other registered platform and forwards data to the PPF. No invoice transits through the PPF itself. Registration is granted by the DGFiP for a renewable three-year term, and the official list is published on impots.gouv.fr (impots.gouv.fr, approved platforms).
One operational detail worth building into your onboarding flow: before the first send to a new French customer, resolve their routing entry in the directory. Directory misses and stale SIREN data were a visible share of the September failures, and a wrong address blocks the invoice without telling the recipient anything.
Using PDF4.dev for the human-readable side
PDF4.dev focuses on the visual rendering. The HTML template plus data model is mapped to a PDF that becomes the human-readable side of the Factur-X file. The CII XML and the embedding step happen outside the PDF4.dev API call, using one of the libraries above.
A minimal EN 16931 invoice template in PDF4.dev:
<style>
body { font-family: 'Inter', sans-serif; padding: 20mm; color: #111827; }
h1 { font-size: 28px; margin-bottom: 4px; }
.meta { color: #6b7280; font-size: 12px; }
table { width: 100%; border-collapse: collapse; margin-top: 24px; }
th, td { padding: 8px 12px; text-align: left; border-bottom: 1px solid #e5e7eb; }
th { background: #f9fafb; font-size: 11px; text-transform: uppercase; }
.totals { margin-top: 16px; width: 50%; margin-left: auto; }
.grand { font-weight: 700; font-size: 18px; }
</style>
<h1>Invoice {{invoice_number}}</h1>
<div class="meta">
Issued {{formatDate issue_date "dd MMM yyyy"}} ·
Due {{formatDate due_date "dd MMM yyyy"}}
</div>
<div style="display: flex; gap: 40px; margin-top: 24px;">
<div>
<div class="meta">From</div>
<strong>{{seller.name}}</strong><br />
{{seller.address}}<br />
VAT {{seller.vat}}
</div>
<div>
<div class="meta">To</div>
<strong>{{buyer.name}}</strong><br />
{{buyer.address}}<br />
VAT {{buyer.vat}}
</div>
</div>
<table>
<thead>
<tr><th>Description</th><th>Qty</th><th>Unit</th><th>VAT</th><th>Total</th></tr>
</thead>
<tbody>
{{#each lines}}
<tr>
<td>{{description}}</td>
<td>{{quantity}}</td>
<td>{{formatCurrency unit_price "EUR" "fr-FR"}}</td>
<td>{{vat_rate}}%</td>
<td>{{formatCurrency line_total "EUR" "fr-FR"}}</td>
</tr>
{{/each}}
</tbody>
</table>
<table class="totals">
<tr><td>Subtotal</td><td>{{formatCurrency subtotal "EUR" "fr-FR"}}</td></tr>
<tr><td>VAT (20%)</td><td>{{formatCurrency vat_total "EUR" "fr-FR"}}</td></tr>
<tr class="grand"><td>Total due</td><td>{{formatCurrency grand_total "EUR" "fr-FR"}}</td></tr>
</table>Rendered via the API:
curl -X POST https://pdf4.dev/api/v1/render \
-H "Authorization: Bearer p4_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"template_id": "tmpl_facturx_en16931",
"data": {
"invoice_number": "INV-2026-0042",
"issue_date": "2026-09-15",
"due_date": "2026-10-15",
"seller": {
"name": "PDF4 SAS",
"address": "Paris, France",
"vat": "FR12345678901"
},
"buyer": {
"name": "Acme France SARL",
"address": "Lyon, France",
"vat": "FR98765432109"
},
"lines": [
{
"description": "API rendering credits, pack of 10000",
"quantity": 1,
"unit_price": 90.00,
"vat_rate": 20,
"line_total": 90.00
},
{
"description": "Priority support, monthly",
"quantity": 1,
"unit_price": 50.00,
"vat_rate": 20,
"line_total": 50.00
}
],
"subtotal": 140.00,
"vat_total": 28.00,
"grand_total": 168.00
}
}' -o invoice-human.pdfThe resulting PDF goes through the Ghostscript PDF/A-3 conversion described in the PDF/A compliance guide, then through the attach step from the previous section. The final file is what an Approved Platform accepts.
Six failure modes that show up in rejection logs
The XML attachment name has to be exactly factur-x.xml. Compliant readers do a case-sensitive filename lookup. Factur-X.xml, FacturX.xml, or invoice.xml all turn the file into a regular PDF with an unrecognized attachment. Older ZUGFeRD readers also accept zugferd-invoice.xml for backwards compatibility, but the canonical name today is factur-x.xml.
The AFRelationship value has to be Alternative, not Data. Some PDF libraries default to Unspecified or Data because those are valid PDF values, but Factur-X requires Alternative to declare that the XML is the same invoice in another representation. A wrong relationship value is the silent failure mode: the PDF opens fine, the human-readable side looks perfect, the accounting system never finds the data.
The CII date format is 102 (YYYYMMDD), not ISO-8601. Putting 2026-09-15 in an IssueDateTime element triggers an XSD violation immediately. The same trap applies to DueDateDateTime and TaxPointDate.
The GuidelineSpecifiedDocumentContextParameter has to match the profile. The most common mismatch is generating EXTENDED-CTC-FR shaped XML with the EN 16931 URN, or the reverse. The Schematron rules differ between profiles, and a mismatch fails validation even if the data looks correct.
Stale validator artifacts. A build still pinned to the 1.07.x Schematron accepts invoices that a platform running 1.09.2 evaluates under different EXTENDED rules and different VAT breakdown cardinality. Pin the artifact version explicitly and treat a version bump as a code change.
The PDF/A-3 declaration in XMP. Playwright and Chromium do not emit PDF/A-3 XMP metadata by default. A PDF that contains the right CII XML attachment but does not declare PDF/A-3 conformance in its XMP block fails the envelope validation step, even though the visual content is fine. The fix is the Ghostscript pass with -dPDFA=3 after rendering.
What is next
September 1, 2027 extends the issuance and e-reporting obligation to SMEs, very small businesses and micro-enterprises in France. Germany's issuance obligation starts on January 1, 2027 for businesses over 800,000 euros annual turnover and on January 1, 2028 for the rest. At the European level, the VAT in the Digital Age package pushes cross-border harmonization toward July 1, 2030.
On the format side, FeRD has signalled a further ZUGFeRD release in autumn 2026 adding gross-invoice support and more EN 16931 functionality, which means another artifact swap before the end of the year.
The architecture holds across all of it: CII XML inside a PDF/A-3 envelope, EN16931 as the default profile, EXTENDED-CTC-FR only when a French rule forces it, validated in CI against pinned artifacts, sent through an Approved Platform, mirrored to the PPF for tax data. The deadline that mattered has passed. What is left is keeping the pipeline current.
Free tools mentioned:
Frequently asked questions
- What is Factur-X?
- Factur-X is the Franco-German hybrid invoice format. A Factur-X file is a single PDF/A-3 document with a UN/CEFACT Cross Industry Invoice (CII) XML attachment named factur-x.xml. The PDF carries the human-readable invoice, the XML carries the legal machine-readable data, and both travel as the same file. ZUGFeRD is the German branding of the same standard.
- What became mandatory in France on September 1, 2026?
- Since September 1, 2026, every VAT-registered business established in France must be able to receive electronic invoices through an Approved Platform. On the same date, large enterprises and mid-sized enterprises (ETI) also became obliged to issue electronic invoices and to transmit e-reporting data. Small, micro and medium businesses join the issuance and e-reporting obligation on September 1, 2027.
- What is the next French e-invoicing deadline?
- September 1, 2027. On that date the issuance obligation and the e-reporting obligation extend to SMEs, very small businesses and micro-enterprises. Until then, those businesses only have to be able to receive electronic invoices, which they already had to be able to do since September 1, 2026.
- What is a hybrid invoice (PDF plus XML)?
- A hybrid invoice is a PDF/A-3 file containing both a printable visual rendering and a structured XML attachment that reproduces the same data in EN 16931 compliant form. Accounting software reads the XML, humans read the PDF, and audit systems archive a single file. Factur-X and ZUGFeRD are the two names for the same hybrid format.
- Which Factur-X profile should I use in France?
- Two semantic profiles pass Approved Platform validation under the French minimum base: EN16931 and EXTENDED-CTC-FR. EN16931 is the default because it carries the full European semantic model and travels across borders unchanged. EXTENDED-CTC-FR, defined by AFNOR XP Z12-012, adds French-specific data and relaxes some EN 16931 business rules for domestic practices. MINIMUM and BASIC WL are header-only profiles intended for cost accounting, not legal invoicing.
- What is the current version of Factur-X and ZUGFeRD?
- Factur-X 1.09.2 and ZUGFeRD 2.5.2, published jointly by FNFE-MPE and FeRD on August 4, 2026 and applicable from September 1, 2026. The release is a technical corrigendum on the 1.09 / 2.5 line, not a new obligation. It fixes EXTENDED profile consistency, VAT breakdown and rounding rules, adds sub-lines and subtotal lines for kits and bundles, and refreshes the XSD and Schematron artifacts for all five profiles.
- How do I embed CII XML inside a PDF/A-3?
- The XML attachment must be named exactly factur-x.xml, declared as a PDF Filespec with AFRelationship set to Alternative, and referenced from the document catalog AF array. The PDF must declare PDF/A-3 conformance in its XMP metadata. Tools such as qpdf, pikepdf, or pdf-lib can attach the file, but the AFRelationship key and the Alternative value must be set explicitly because most generic attach commands default to Unspecified.
- Do I have to send invoices through the PPF?
- No. The free issuance and reception service the Portail Public de Facturation was originally meant to offer was dropped by the DGFiP in October 2024. The PPF keeps the central recipient directory and the tax data concentrator, and no invoice transits through it. Businesses send and receive through Approved Platforms (Plateformes Agréées, formerly PDP), which exchange invoices with each other and forward lifecycle and tax data to the PPF.
- What if my customer is in Germany rather than France?
- Factur-X and ZUGFeRD share the same XML schema and the same PDF/A-3 envelope, so a Factur-X 1.09.2 file is also a valid ZUGFeRD 2.5.2 file. Germany has required reception of EN 16931 invoices since January 1, 2025 and phases issuance from January 1, 2027. The same hybrid PDF satisfies both jurisdictions if the profile is EN16931 or higher, but EXTENDED-CTC-FR carries French-specific data that only makes sense on the French side.
- Are there penalties if I was not ready on September 1, 2026?
- The statutory scale is 50 euros per invoice not issued electronically and 500 euros per missing e-reporting transmission, each capped at 15,000 euros per calendar year, plus a 500 euro fine (then 1,000 euros every three months) for failing to connect to an Approved Platform after a formal notice. The DGFiP announced in July 2026 that it would apply a tolerance to good-faith businesses hitting startup difficulties, and the law waives a first offence that is corrected spontaneously or within thirty days of an administration request.
Start generating PDFs
Build PDF templates with a visual editor. Render them via API from any language in ~300ms.



