Since 1 September 2026, every VAT-registered business in France must be able to receive structured e-invoices, and large and mid-sized enterprises must be able to issue them [1]. If your SaaS still emails HTML-rendered PDFs to French customers, those invoices stopped being legal weeks ago. The obligation is not suspended, even though no penalty will be applied to any business in 2026 [2].
The French e-invoicing reform that has been delayed since 2023 finally took effect. VAT-registered businesses must now receive invoices in one of three structured formats: UBL 2.1, CII, or Factur-X [1]. Large and mid-sized enterprises had to start issuing through approved platforms on the same date [1]. SMEs and micro-enterprises have until 1 September 2027 to begin issuing [1].
For invoices within the issuing obligation, an ordinary email attachment has not been a compliant channel since 31 August 2026 [2]. Instead, an approved platform (PA) — a private operator registered by the DGFiP for a renewable three-year term — is the only transmission channel [2]. The Finance Act for 2026 replaced the earlier term PDP (plateforme de dématérialisation partenaire) with plateforme agréée (PA) throughout the tax code [2].
The French ministry announced on 1 September 2026 that no penalty would be applied to any business in 2026, and the DGFiP practical guide sets out what the administration will weigh: real, documented difficulties followed by corrective action [2]. When penalties do begin, the amended Loi de Finances pour 2026 sets them at €50 per invoice, up from €15, with an annual cap of €15,000 [3].
Factur-X is a hybrid format: a human-readable PDF/A-3 container with an embedded UN/CEFACT CII XML file carrying the structured invoice data [1]. The arrêté of 27 July 2026 sets five accepted formats; the hybrid format must conform to AFNOR standard XP Z12-012 [2].
PDF/A-3 is specifically required because it is the only PDF/A variant that permits embedding files such as the invoice XML [1]. Since ZUGFeRD 2.0, Factur-X and Germany's ZUGFeRD share the same UN/CEFACT CII XML syntax and EN 16931 semantic standard, making well-formed files structurally interchangeable [1]. Factur-X defines multiple profiles, with EN 16931 (Comfort, ~100 fields) recommended for France [4].
The visual layer is PDF/A-3. The compliance layer is valid CII XML. Both must be correct.
Generating a Factur-X invoice is not simply "print to PDF and attach an XML file." Four specific mechanical requirements determine whether a file passes validation:
factur-x.xml and declared in the /AF (Associated Files) dictionary.AFRelationship value must match the profile: Data for MINIMUM and BASIC WL; Alternative for BASIC, EN 16931, and EXTENDED. Check the default in your library — some default to Data for all profiles, and not every validator catches this mismatch even though it fails specification compliance.fx:DocumentType, DocumentFileName, Version, and ConformanceLevel with exact spelling, including the space in 'EN 16931'. A typo here fails veraPDF structural validation.You can still design invoices with CSS, custom fonts, and responsive layouts. But the PDF that reaches your customer must be normalised to PDF/A-3b, and the XML must be embedded with profile-correct metadata.
If you already generate invoice PDFs from HTML templates, you can adapt your pipeline rather than replace it. The pattern is: one data source produces both the human-readable PDF and the structured XML, then a normalisation step binds them together.
Render your invoice from an HTML template as before. MarkupGo's API accepts a template ID and context data, using Handlebars syntax with {{ variable }} placeholders and {{#each items}} loops for line items [5]. The online editor lets you iterate designs without touching compliance code [5].
After rendering, normalise to PDF/A-3b. Tools like pikepdf can embed fonts, set the OutputIntent, and fix XMP metadata. Generate valid EN 16931 CII XML from the same invoice data source — this is your accounting system's responsibility, not the renderer's.
Embed the CII XML with the profile-correct AFRelationship. Validate the container with veraPDF and the structure/XML with Mustang. You must ensure your data pipeline feeds identical values to both outputs.
France is not an outlier. Every German business has had to be able to receive e-invoices since 1 January 2025; suppliers with over €800,000 turnover in 2026 must issue from 1 January 2027, and from 1 January 2028 practically all domestic B2B invoices are covered [6].
Under EU ViDA, mandatory B2B e-invoicing and Digital Reporting Requirements for intra-Community transactions take effect 1 July 2030, with full harmonisation of domestic reporting systems by 1 January 2035 [7].
MarkupGo handles the HTML-to-PDF rendering half of this pipeline: template with Handlebars variables, loops for line items, API call with template ID and context [5]. Reusable templates and the online editor let you iterate invoice designs without touching compliance code [8][5]. Integration with Make.com and Google Sheets automates generation from spreadsheet rows [8].
The PDF/A-3 normalisation and XML embedding steps sit downstream of rendering. MarkupGo gives you the visual layer; you add the structured payload. Existing blog guides cover Stripe invoices [8], Google Sheets invoices, and QR-code invoices — the same templates, now feeding a hybrid pipeline.
A typical MarkupGo API call for the rendering stage:
fetch("https://api.markupgo.com/api/v1/pdf", {
method: "POST",
headers: {
"x-api-key": process.env.MARKUPGO_API_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
source: {
type: "template",
data: {
id: process.env.INVOICE_TEMPLATE_ID,
context: {
// invoice data matching your template's Handlebars variables
invoice_number: "FR-2026-00042",
items: [
// see MarkupGo's API reference for full context structure
]
}
}
}
})
})
.then(res => res.json())
.then(task => {
// task.url contains the rendered PDF
// pass this to your PDF/A-3 normalisation and XML embedding step
});
The context object must match your template's {{ variable }} placeholders exactly. For line items, use {{#each items}} with fields like item_name, qty, rate, and amount [5].
Audit whether any of your customers are French VAT-registered or mid-size/large enterprises. Check if your current PDF output passes PDF/A-3b — raw Chromium does not install or embed fonts by itself. Identify who produces your EN 16931 CII or UBL XML; if nobody, that is your real blocker.
Build the hybrid pattern now: one data source → structured XML + human-readable PDF. Test with veraPDF and Mustang before your first production invoice. The 2026 penalty holiday is not a reason to wait; it is time to build without the pressure of immediate fines.
Leave a comment if you have implemented Factur-X or ZUGFeRD in production — which normalisation tool did you choose, and what validation failures caught you first?