France
Factur-X e-invoicing requirements for France, with Beliq configuration examples.
France commonly uses Factur-X. It is a hybrid PDF format (technically aligned with ZUGFeRD) that embeds CII D22B XML in a PDF/A-3 document. Beliq targets Factur-X 1.09.2 (jointly published with ZUGFeRD 2.x).
Factur-X is jointly maintained by the FNFE-MPE (France) and FeRD (Germany) and is fully aligned with EN 16931.
Factur-X 1.09.2 profiles
| Profile | Beliq value | Description | Status in Beliq |
|---|---|---|---|
| Minimum | minimum |
Minimal structured data — invoice number, date, and totals only | Supported (via Mustangproject — see secondary-source note below) |
| Basic WL | basicwl |
Header-level data without individual line items | Supported |
| Basic | basic |
Full header and line items | Supported (via Mustangproject — see secondary-source note below) |
| EN 16931 (Comfort) | en16931 |
Full EN 16931 compliance — recommended | Supported |
| Extended | extended |
Additional fields beyond EN 16931, with optional sub-line nesting | Supported |
| EXTENDED-CTC-FR | extended-ctc-fr |
EXTENDED + the French B2B reform CTC overlay (BR-FR-CTC + EXTENDED-CTC-FR Schematron) | Supported |
minimum and basicwl are reduced profiles (header-only, and without individual line items) and are not complete EN 16931 invoices. Pick them only when the receiver specifically expects that profile; see the format reference for the per-profile compliance breakdown.
For most use cases, en16931 is the recommended profile. Pick extended-ctc-fr when the receiver requires the French B2B reform CTC overlay. The Factur-X format reference carries the per-profile element layout, the CustomizationID URNs and the pinned artefact versions.
MINIMUM and BASIC — secondary source
The FNFE-MPE / FeRD joint pack distributes the BASIC_WL, EN 16931 and EXTENDED Schematron and XSDs via direct download. The MINIMUM and BASIC profile artifacts are gated behind an email-request information package on the FNFE-MPE side. Beliq sources MINIMUM and BASIC Schematron and per-profile XSDs from Mustangproject core-2.26.0 (Apache-2.0) — Mustangproject is listed by FNFE-MPE itself as a recommended downstream consumer and re-publishes the same artifacts at matching upstream tags. The Mustangproject provenance is recorded with SHA-pinned per-file paths.
All five Factur-X 1.09.2 profiles run through the same XSD + Schematron pipeline; documents arriving with a MINIMUM, BASIC, BASIC_WL, EN16931, or EXTENDED CustomizationID are validated against the matching profile rules without operator intervention.
Factur-X sits at Authority-checked, on the builder-round-trip tier: the FNFE-MPE / FeRD Schematron that judges your document is the authority’s own, pinned by version and hash, but FNFE-MPE publishes no per-rule test corpus to check it against. Correctness rests on the authority’s positive sample invoices, round-trips through Beliq’s own generator, and a spec-derived negative fixture cross-checked against the Mustangproject validator. The missing upstream corpus is re-checked quarterly. See how verification works for the tier definitions.
Generating Factur-X invoices
Use standard: "facturx" with output: "pdf":
curl -X POST https://api.beliq.eu/v1/generate \
-H "Authorization: Bearer blq_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"standard": "facturx",
"profile": "en16931",
"output": "pdf",
"invoice": {
"number": "FA-2026-0123",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"seller": {
"name": "Exemple SARL",
"vatId": "FR12345678901",
"email": "facturation@exemple.example",
"address": {
"street": "12 Rue de la Paix",
"city": "Paris",
"postalCode": "75002",
"countryCode": "FR"
}
},
"buyer": {
"name": "Client SAS",
"vatId": "FR98765432109",
"address": {
"street": "8 Avenue des Champs-Élysées",
"city": "Paris",
"postalCode": "75008",
"countryCode": "FR"
}
},
"lines": [
{
"description": "Prestation de conseil — Avril 2026",
"quantity": 5,
"unitCode": "DAY",
"unitPrice": 800.00,
"lineTotal": 4000.00,
"vatRate": 20,
"vatCategoryCode": "S"
}
],
"taxSummary": [
{ "vatCategoryCode": "S", "vatRate": 20, "taxableAmount": 4000.00, "taxAmount": 800.00 }
],
"paymentMeans": {
"typeCode": "30",
"iban": "FR7630006000011234567890189",
"bic": "BNPAFRPPXXX"
},
"paymentTerms": "Net 30 jours",
"totalNetAmount": 4000.00,
"totalTaxAmount": 800.00,
"totalGrossAmount": 4800.00
}
}' --output facture.pdfimport { writeFile } from 'node:fs/promises';
import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const generated = await beliq.generate({
standard: 'facturx',
profile: 'en16931',
output: 'pdf',
invoice: {
number: 'FA-2026-0123',
issueDate: '2026-04-13',
dueDate: '2026-05-13',
currencyCode: 'EUR',
seller: {
name: 'Exemple SARL',
vatId: 'FR12345678901',
email: 'facturation@exemple.example',
address: { street: '12 Rue de la Paix', city: 'Paris', postalCode: '75002', countryCode: 'FR' },
},
buyer: {
name: 'Client SAS',
vatId: 'FR98765432109',
address: {
street: '8 Avenue des Champs-Élysées',
city: 'Paris',
postalCode: '75008',
countryCode: 'FR',
},
},
lines: [
{
description: 'Prestation de conseil — Avril 2026',
quantity: 5,
unitCode: 'DAY',
unitPrice: 800.00,
lineTotal: 4000.00,
vatRate: 20,
vatCategoryCode: 'S',
},
],
taxSummary: [{ vatCategoryCode: 'S', vatRate: 20, taxableAmount: 4000.00, taxAmount: 800.00 }],
paymentMeans: { typeCode: '30', iban: 'FR7630006000011234567890189', bic: 'BNPAFRPPXXX' },
paymentTerms: 'Net 30 jours',
totalNetAmount: 4000.00,
totalTaxAmount: 800.00,
totalGrossAmount: 4800.00,
},
});
await writeFile('facture.pdf', generated.bytes);import os
from pathlib import Path
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
generated = beliq.generate(
standard="facturx",
profile="en16931",
output="pdf",
invoice={
"number": "FA-2026-0123",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"seller": {
"name": "Exemple SARL",
"vatId": "FR12345678901",
"email": "facturation@exemple.example",
"address": {
"street": "12 Rue de la Paix",
"city": "Paris",
"postalCode": "75002",
"countryCode": "FR",
},
},
"buyer": {
"name": "Client SAS",
"vatId": "FR98765432109",
"address": {
"street": "8 Avenue des Champs-Élysées",
"city": "Paris",
"postalCode": "75008",
"countryCode": "FR",
},
},
"lines": [
{
"description": "Prestation de conseil — Avril 2026",
"quantity": 5,
"unitCode": "DAY",
"unitPrice": 800.00,
"lineTotal": 4000.00,
"vatRate": 20,
"vatCategoryCode": "S",
},
],
"taxSummary": [{"vatCategoryCode": "S", "vatRate": 20, "taxableAmount": 4000.00, "taxAmount": 800.00}],
"paymentMeans": {"typeCode": "30", "iban": "FR7630006000011234567890189", "bic": "BNPAFRPPXXX"},
"paymentTerms": "Net 30 jours",
"totalNetAmount": 4000.00,
"totalTaxAmount": 800.00,
"totalGrossAmount": 4800.00,
},
)
Path("facture.pdf").write_bytes(generated.content)XML output
To generate just the CII XML without the PDF wrapper:
curl -X POST https://api.beliq.eu/v1/generate \
-H "Authorization: Bearer blq_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"standard": "facturx",
"profile": "en16931",
"output": "xml",
"invoice": {
"number": "FA-2026-0123",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"seller": {
"name": "Exemple SARL",
"vatId": "FR12345678901",
"address": { "street": "12 Rue de la Paix", "city": "Paris", "postalCode": "75002", "countryCode": "FR" }
},
"buyer": {
"name": "Client SAS",
"vatId": "FR98765432109",
"address": { "street": "8 Avenue des Champs-Élysées", "city": "Paris", "postalCode": "75008", "countryCode": "FR" }
},
"lines": [
{
"description": "Prestation de conseil — Avril 2026",
"quantity": 5,
"unitCode": "DAY",
"unitPrice": 800.00,
"lineTotal": 4000.00,
"vatRate": 20,
"vatCategoryCode": "S"
}
],
"taxSummary": [
{ "vatCategoryCode": "S", "vatRate": 20, "taxableAmount": 4000.00, "taxAmount": 800.00 }
],
"totalNetAmount": 4000.00,
"totalTaxAmount": 800.00,
"totalGrossAmount": 4800.00
}
}'import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const generated = await beliq.generate({
standard: 'facturx',
profile: 'en16931',
output: 'xml',
invoice: {
number: 'FA-2026-0123',
issueDate: '2026-04-13',
dueDate: '2026-05-13',
currencyCode: 'EUR',
seller: {
name: 'Exemple SARL',
vatId: 'FR12345678901',
address: { street: '12 Rue de la Paix', city: 'Paris', postalCode: '75002', countryCode: 'FR' },
},
buyer: {
name: 'Client SAS',
vatId: 'FR98765432109',
address: {
street: '8 Avenue des Champs-Élysées',
city: 'Paris',
postalCode: '75008',
countryCode: 'FR',
},
},
lines: [
{
description: 'Prestation de conseil — Avril 2026',
quantity: 5,
unitCode: 'DAY',
unitPrice: 800.00,
lineTotal: 4000.00,
vatRate: 20,
vatCategoryCode: 'S',
},
],
taxSummary: [{ vatCategoryCode: 'S', vatRate: 20, taxableAmount: 4000.00, taxAmount: 800.00 }],
totalNetAmount: 4000.00,
totalTaxAmount: 800.00,
totalGrossAmount: 4800.00,
},
});
// `xml` is the same document curl writes to stdout.
console.log(generated.xml);import os
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
generated = beliq.generate(
standard="facturx",
profile="en16931",
output="xml",
invoice={
"number": "FA-2026-0123",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"seller": {
"name": "Exemple SARL",
"vatId": "FR12345678901",
"address": {
"street": "12 Rue de la Paix",
"city": "Paris",
"postalCode": "75002",
"countryCode": "FR",
},
},
"buyer": {
"name": "Client SAS",
"vatId": "FR98765432109",
"address": {
"street": "8 Avenue des Champs-Élysées",
"city": "Paris",
"postalCode": "75008",
"countryCode": "FR",
},
},
"lines": [
{
"description": "Prestation de conseil — Avril 2026",
"quantity": 5,
"unitCode": "DAY",
"unitPrice": 800.00,
"lineTotal": 4000.00,
"vatRate": 20,
"vatCategoryCode": "S",
},
],
"taxSummary": [{"vatCategoryCode": "S", "vatRate": 20, "taxableAmount": 4000.00, "taxAmount": 800.00}],
"totalNetAmount": 4000.00,
"totalTaxAmount": 800.00,
"totalGrossAmount": 4800.00,
},
)
# `xml` is the same document curl writes to stdout.
print(generated.xml)French B2B reform (CTC) readiness
France’s B2B e-invoicing reform replaces unstructured invoices with EN 16931-compliant Factur-X documents transported through certified Plateformes Agréées (PA). The current legal timeline (DGFiP / AIFE) is:
| Date | What changes |
|---|---|
| 1 September 2026 | All businesses must be able to receive; large enterprises and mid-caps (ETI) must issue and e-report. |
| 1 September 2027 | Small and medium enterprises (PME) and micro-enterprises (TPE) must issue and e-report. |
The 1 September 2026 and 2027 calendar was reconfirmed in April 2025; a further delay was rejected. Dates can still move by decree, so re-confirm against DGFiP before relying on them.
Last verified against DGFiP / AIFE and the European Commission eInvoicing country page on 24 August 2026. Official source.
Always check the official impots.gouv.fr e-invoicing portal for the latest dates and the B2B “Spécifications externes” v3.2 for the full technical requirements.
What Beliq covers today
For the French B2B reform, Beliq generates Factur-X 1.09.2 documents that pass the FNFE-MPE BR-FR-CTC Flux 2 Schematron. Concretely:
- We emit Factur-X 1.09.2 / D22B documents (and PDF/A-3 hybrids) that satisfy the EN 16931 baseline.
- We validate against FNFE-MPE’s BR-FR-CTC Flux 2 Schematron (
france_ctc_schematron, currently 1.4.0.04) on any of three triggers: you sendfranceCtc=true; the document’s BT-24 CustomizationID is the EXTENDED-CTC-FR one; or its BT-23 BusinessProcess carries a cadre de facturation code from the closed XP Z12-012 list (B1,S1,M1,B2,S2,M2,S3,B4,S4,M4,S5,S6,B7,S7,B8,S8,M8,B9,S9,M9). Any of the twenty turns CTC mode on;S8/B8/M8are the multi-vendor subset, not the whole trigger. - We then additionally apply the EXTENDED-CTC-FR overlay, on two triggers of its own: the document is on the Factur-X EXTENDED profile (CII), or it declares the EXTENDED-CTC-FR CustomizationID outright. The second arm is the only route for a UBL document, which carries no Factur-X profile.
- On generate,
facturxProfile: "extended-ctc-fr"turns CTC mode on by itself, so you do not also have to sendfranceCtc: true. - The FR-specific structural fields (SIREN / SIRET on seller and buyer, French VAT codes, Flux 2 process codes, line-level legal IDs and parent-line linkage) are recognised by both the builder and the validator, with rule IDs surfaced in the validation result.
# Opt in to the BR-FR-CTC overlay when validating an existing document
curl -X POST 'https://api.beliq.eu/v1/validate?franceCtc=true' \
-H 'Authorization: Bearer blq_live_abc123...' \
-H 'Content-Type: application/xml' \
--data-binary @facture.xmlimport { readFile } from 'node:fs/promises';
import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const result = await beliq.validate(await readFile('facture.xml'), { franceCtc: true });
console.log(result.valid, result.format, result.schematronVersion);
for (const issue of result.errors) console.log(issue.ruleId, issue.message);import os
from pathlib import Path
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
result = beliq.validate(Path("facture.xml").read_bytes(), france_ctc=True)
print(result.valid, result.format, result.schematron_version)
for issue in result.errors:
print(issue.rule_id, issue.message)// Generate a CTC-enabled invoice
{
"standard": "facturx",
"facturxProfile": "extended-ctc-fr",
"output": "pdf",
"invoice": {
/* …seller / buyer with SIREN/SIRET and FR VAT IDs, lines, totals… */
"franceCtc": true,
"businessProcessId": "B8"
}
}Which French flows need a Plateforme Agréée
The reform’s perimeter is drawn by establishment in France, not by nationality, VAT number, or invoice currency. That splits French traffic into three cases, and only one of them is regulated:
| Flow | In the reform’s perimeter? | How it travels |
|---|---|---|
| Seller established in France → buyer established in France | Yes | Must go through a Plateforme Agréée (PA) |
| Seller not established in France → French buyer | No | Ordinary Peppol, BIS Billing 3.0 |
| Seller established in France → foreign buyer | No | Ordinary Peppol |
Because establishment is the test, a foreign company with a French branch is inside the perimeter even though it is not a French company, and a company holding a French VAT number without a French establishment is outside it. Businesses with no French establishment are excluded from French e-invoicing altogether rather than given a later deadline (DGFiP FAQ, 15 June 2026, Q1.6); they may still owe e-reporting where they are liable for French VAT.
For the two unregulated cases, France changes nothing: those are cross-border Peppol invoices, and managed delivery will route them on the peppol network like any other. For the regulated case it will not. POST /v1/send and POST /v1/transmissions refuse a French domestic flow on the peppol network with 409 FRENCH_DOMESTIC_FLOW, and nothing is queued or billed. That is not a verdict on the document — the invoice may be perfectly valid — it is a refusal of the route: a domestic invoice that reaches the buyer over plain Peppol still leaves the seller outside the reform. See transmission errors.
Once the PA lane is live, a second check runs on it, and it is about the document rather than the route. A plateforme agréée refuses an invoice that trips any BR-FR-CTC Flux 2 rule, whatever severity the French rule pack assigns it — and its refusal burns the invoice number, because a French number is unique on (number, supplier SIREN, invoice year) and a rejected invoice must be reissued under a new one. Beliq therefore checks its own verdict before the send: 422 FRANCE_CTC_BLOCKING_FINDINGS lists the rules to correct, and 422 FRANCE_CTC_NOT_JUDGED means the invoice carries neither BT-23 nor the EXTENDED-CTC-FR profile, so nothing judged it against the French rules at all. Note that POST /v1/validate can report valid: true for a document this refuses: the pack currently flags most of these rules as warnings, which is why the validation result carries franceCtcBlockingRuleIds as a separate answer. Clearing the check is not a promise of acceptance — the platform runs its own rule packs and its verdict is its own.
If a PA does reject an invoice, resending the same bytes is refused with 409 FRANCE_INVOICE_NUMBER_BURNED: issue a corrected invoice under a new number instead. The platform’s own duplicate check does not stop the reuse, which is exactly why the guard is on our side.
Treat the refusal as a safeguard, not as a compliance determination. Where we have recorded where a party is established, that is what the check uses, for both the seller and the buyer. Where we have not, it falls back to proxies for establishment rather than the test itself, so the check can miss a case they cannot see: for your own registration, the registered country it carries; for your buyer, the addressing scheme alone, since the country on someone else’s registration is neither the right test nor ours to read on your behalf. You hold the establishment facts; tell us and we will record them. The French domestic route is the partner PA lane described below.
What Beliq does not do (transmission / Annuaire / e-reporting)
Beliq is not a Plateforme Agréée (PA) immatriculée operator and does not (yet) intermediate transmission through the AIFE network. Specifically, the following are out of scope of this release:
- Plateforme Agréée (PA) immatriculation with AIFE (a separate regulatory and operational program).
- Operating the AIFE Annuaire (recipient lookup) interface.
- The CDAR (Cross-Domain Acknowledgement and Response) message envelope used between Plateformes Agréées.
- E-reporting flows (Flux 8 / 9 / 10) used for transaction reporting to DGFiP.
If your workflow requires a registered Plateforme Agréée (PA) today, please pair Beliq’s compliant Factur-X output with a partner PA for transmission. Managed delivery through a partner PA is in build, targeting Q4 2026 and subject to certification. Reach out if you would like us to track your PA requirements as we expand this work.
French VAT specifics
| VAT rate | Category code | Description |
|---|---|---|
| 20% | S |
Standard rate |
| 10% | S |
Intermediate rate |
| 5.5% | S |
Reduced rate |
| 2.1% | S |
Super-reduced rate |
| 0% | Z |
Zero-rated (e.g. intra-community supplies) |
| 0% | AE |
Reverse charge |
| 0% | E |
Exempt |
Use the appropriate vatRate and vatCategoryCode combination on each invoice line.
Parsing Factur-X invoices
Upload a Factur-X PDF to extract the embedded data:
curl -X POST https://api.beliq.eu/v1/parse \
-H "Authorization: Bearer blq_live_abc123..." \
-H "Content-Type: application/octet-stream" \
--data-binary @facture.pdfimport { readFile } from 'node:fs/promises';
import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const parsed = await beliq.parse(await readFile('facture.pdf'));
console.log(parsed.format, parsed.profileDetected);
console.log(parsed.invoice);import os
from pathlib import Path
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
parsed = beliq.parse(Path("facture.pdf").read_bytes())
print(parsed.format, parsed.profile_detected)
print(parsed.invoice)The engine extracts the factur-x.xml attachment from the PDF and returns the normalized JSON invoice data.
Validation
Beliq validates Factur-X 1.09.2 invoices against:
- CII D22B XSD schema (the per-profile XSD subset is used when the document declares a Factur-X CustomizationID).
- EN 16931 core Schematron rules (currently v1.3.16).
- The Factur-X 1.09.2 profile-specific Schematron (BASIC_WL / EN16931 / EXTENDED), vendored from FNFE-MPE / FeRD.
- The FNFE-MPE BR-FR-CTC Flux 2 overlay when
franceCtc=trueis requested, when BT-24 is the EXTENDED-CTC-FR CustomizationID, or when BT-23 carries any of the twenty XP Z12-012 cadre de facturation codes. - The FNFE-MPE EXTENDED-CTC-FR overlay on top of (4) when the document is on the Factur-X EXTENDED profile or declares the EXTENDED-CTC-FR CustomizationID.
See validation artifacts for the exact versions in use.
Resources
- Factur-X specification — official FNFE-MPE documentation
- DGFiP e-invoicing reform portal (impots.gouv.fr)
- EN 16931 business rules — CEN/TC 434 Schematron rules