Factur-X Validation for the French e-invoicing reform
Validate Factur-X invoices against the profile they declare, MINIMUM, BASIC WL, BASIC, EN 16931 or EXTENDED, using the official FNFE-MPE artifacts, and confirm they will be accepted by Chorus Pro and your PDP before you transmit. Structured JSON, returned in under two seconds.
The InvoiceXML Factur-X API runs the EN 16931 and Factur-X rule checks a Plateforme de Dematerialisation Partenaire applies at intake, every violation reported with its rule ID, the validation layer it came from, and the XPath location. Because Factur-X is the French branding of the same hybrid PDF/A-3 plus CII format as ZUGFeRD, a file that passes here is valid on both sides of the Rhine.
curl -X POST https://api.invoicexml.com/v1/validate/facturx \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "[email protected]"
{ "valid": true, "data": { "hasEmbeddedXml": true, "profile": "en16931", "customizationId": "urn:cen.eu:en16931:2017" }, "errors": [], "warnings": [] }
Try it live, no API key required
This runs the same POST /v1/validate/facturx endpoint your integration will call. Drop any Factur-X PDF to see the full validation response and whether it would clear Chorus Pro and your PDP.
Drop your Factur-X PDF here
or browse files to upload
POST /v1/validate/facturx · Accepted format: PDF · Max 20 MB
Not just pass or fail. A full Factur-X compliance report.
Most validators tell you an invoice failed and leave you to dig through Schematron output. The InvoiceXML Factur-X API returns a complete report array instead: one row for every EN 16931 Business Term it found in your invoice, each with the extracted value and a pass or fail verdict. It is the raw material for an audit-ready compliance view your finance team and your PDP can both read, with zero XML parsing on your side.
Factur-X Compliance Report
facture-facturx.pdf · Atelier Lyonnais SARL · profile EN 16931
| Status | Business Term | Field | Value |
|---|---|---|---|
| BT-1 Invoice number | invoiceNumber | FAC-2026-0412 | |
| BT-5 Invoice currency | currency | EUR | |
| BT-27 Seller name | seller.name | Missing. The seller must have a name. | |
| BT-31 Seller VAT identifier | seller.vatIdentifier | FR42921835000 | |
| BT-112 Invoice total with VAT | totals.grandTotalAmount | 1190.00 | |
| BT-131 Line net amount, line 2 | lines[1].lineNetAmount | Missing. Document total cannot be reconciled. |
Rendered from the report array. Each row is one object: code, name, section, path, value, isValid, and error.
PDP pre-flight gate
Branch on the valid boolean before you hand a Factur-X file to your Plateforme de Dematerialisation Partenaire or to Chorus Pro. Catch the two red rows in your own system rather than receiving a rejection lifecycle status hours later, and resubmit clean the first time.
Inline form highlighting
The path on every row, and the fields array on every friendly error, map directly to your invoice form inputs. Mark the failing field red and show the message beside it, so the supplier fixes the exact value (a missing SIREN-derived VAT id, an unreconciled line amount) that failed.
Audit trails for the reform
Store the report alongside each archived Factur-X invoice as machine-readable proof of the compliance check. Under the French reform's archiving and e-reporting obligations, when an auditor or your PDP queries a document years later, the evidence of the rules it passed is already on file.
Validate Factur-X REST API Request
Validating your Factur-X invoice programatically takes just a couple of lines of code:
$ curl -X POST https://api.invoicexml.com/v1/validate/facturx \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "[email protected]"
You only send the file. The API detects the Factur-X profile and version automatically and returns the detected values.
Validate Factur-X API Response
Both valid and invalid invoices return HTTP 200. Branch on the valid boolean to determine compliance. The response includes the detected conformance level (e.g. EN16931, BASIC, EXTENDED) so you know exactly which Factur-X profile was checked.
Validation errors come in two formats: raw Schematron codes for machines, and a friendly error message array with easy to read and comprehend messages ready to display directly to end users, no more cryptic rule IDs or XPath expressions.
Each friendly error also carries btCodes and a fields array, the dotted JSON paths the error maps to. A front-end form can read fields to highlight the exact input that failed, for example seller.name or lines[1].lineNetAmount, and show the message right beside it. Every response, valid or not, also includes a report array: one row per EN 16931 Business Term with its value and a pass or fail flag, ready to render as a compliance table.
Valid Factur-X Invoice Response
// 200 OK { "valid": true, "detail": "Your invoice is Factur-X, ZUGFeRD and EN16931 compliant", "data": { "schemaValid": true, "schematronValid": true, "conformanceLevel": "EN16931", "hasEmbeddedXml": true, "profile": "en16931", "customizationId": "urn:cen.eu:en16931:2017" }, "errors": [], "warnings": [], "report": [ { "code": "BT-1", "name": "Invoice number", "section": "header", "path": "invoiceNumber", "value": "FAC-2026-0412", "isValid": true, "errors": [], "warnings": [] } // one row per EN 16931 business term, see the compliance report section below ] }
Invalid Factur-X Invoice Response
// 200 OK { "valid": false, "detail": "Validation failed with 3 error(s)", "data": { "schemaValid": true, "schematronValid": false, "conformanceLevel": "EN16931", "hasEmbeddedXml": true, "profile": "en16931", "customizationId": "urn:cen.eu:en16931:2017" }, "errors": [ { "rule": "BR-01", "layer": "en16931", "line": null, "message": "The invoice is missing a specification identifier.", "btCodes": ["BT-24"], "fields": ["specificationId"], "raw": "[BR-01] EN16931: An invoice shall have a specification identifier (at /*:CrossIndustryInvoice/*:ExchangedDocumentContext)." }, { "rule": "BR-06", "layer": "en16931", "line": null, "message": "The seller must have a name.", "btCodes": ["BT-27"], "fields": ["seller.name"], "raw": "[BR-06] EN16931: An invoice shall contain the seller name (at /*:CrossIndustryInvoice/.../*:SellerTradeParty)." }, { "rule": "BR-FR-04", "layer": "facturx", "line": null, "message": "A seller VAT identifier or French SIREN/SIRET legal identifier is required for B2B invoices.", "btCodes": ["BT-31", "BT-30"], "fields": ["seller.vatIdentifier"], "raw": "[BR-FR-04] Factur-X: The Seller shall be identified by a VAT identifier or a legal registration identifier (at /*:CrossIndustryInvoice/.../*:SellerTradeParty)." } ], "warnings": [], "report": [ // full field-by-field report, see the compliance report section below { "code": "BT-27", "name": "Seller name", "section": "seller", "path": "seller.name", "value": null, "isValid": false, "errors": ["The seller must have a name."], "warnings": [] } ] }
The five Factur-X profiles, and which ones count as e-invoices
FNFE-MPE defines five profiles that climb in data richness: MINIMUM and BASIC WL (without lines) carry header and total data only and are intended as e-reporting or accounting extracts, not full invoices. BASIC adds line items. EN 16931 is the European semantic core, fully compliant with the directive and the profile most B2B and B2G exchanges should target. EXTENDED carries the additional Franco-German fields beyond the norm. The API reads the SpecificationIdentifier, validates against exactly the matching profile, and flags a PROFILE-SCOPE warning on MINIMUM and BASIC WL files so you know they will not be accepted where a complete invoice is required. Because Factur-X and ZUGFeRD share the same profile ladder and CII syntax, the same file validates identically under both names.
What the Factur-X validation API checks
CII XSD Schema
Validates the embedded factur-x.xml against the UN/CEFACT CII D16B XSD schema published in the FNFE-MPE Factur-X distribution. Catches malformed XML, missing required elements, incorrect data types, and namespace errors before Schematron runs.
EN 16931 Schematron
Validates all 200+ EN 16931 business rules (BR-xx codes), the European semantic core the French reform builds on. Includes arithmetic rules like BR-CO-14 (invoice total VAT must equal sum of VAT breakdown amounts), conditional rules like BR-AE-05 (reverse charge VAT rate must be zero), and party rules like BR-01 (specification identifier must be present).
Factur-X Profile Rules
Detects the declared profile (MINIMUM, BASIC WL, BASIC, EN 16931, EXTENDED) and validates that the invoice only contains fields permitted by that profile, plus the French BR-FR Factur-X constraints. A MINIMUM invoice that includes line items fails here, and a B2B invoice missing a VAT or SIREN/SIRET legal identifier is flagged before it reaches a PDP.
Attachment and Syntax Guard
Finds the embedded invoice under any of the recognised attachment names: factur-x.xml, the legacy zugferd-invoice.xml, and xrechnung.xml. A PDF with no invoice attachment gets a clear PDF-EMBED finding, and one whose attachment is UBL instead of CII gets a PDF-EMBED-SYNTAX finding pointing to the UBL validator, never a cryptic schema error.
REST API Response schema
Both valid and invalid invoices return HTTP 200. Use the valid boolean to branch your logic. The response includes the detected conformance level and human-readable error messages with optional line numbers, designed so you can render them directly in your UI without post-processing. Create/convert endpoints return HTTP 400 with the same errors structure on validation failure.
| Field | Type | Description |
|---|---|---|
| Always present | ||
| valid | boolean | Primary flag to branch on. true when compliant, false when errors found. |
| detail | string | Human-readable summary, e.g. "Your invoice is Factur-X compliant…" or "Validation failed with 2 error(s)". |
| data.conformanceLevel | string | Detected conformance level, e.g. EN16931, BASIC, EXTENDED. |
| data.schemaValid | boolean | XSD schema check passed. |
| data.schematronValid | boolean | Schematron business rules check passed. |
| data.profile | string? | Detected Factur-X profile, e.g. minimum, basicwl, basic, en16931, extended. |
| data.customizationId | string? | The SpecificationIdentifier read from the XML, e.g. urn:cen.eu:en16931:2017. |
| Findings (errors and warnings) | ||
| errors | object[] | Flat array of blocking finding objects. Empty when the invoice is valid. |
| warnings | object[] | Flat array of advisory finding objects. May contain entries even when the invoice is valid. |
| [].rule | string | Rule identifier, e.g. BR-01, BR-CO-14, BR-FR-04. |
| [].layer | string | Which rule set raised the finding: xsd, en16931, or facturx. |
| [].line | int? | Invoice line item number, or null for document-level findings. |
| [].message | string | Human-readable, friendly description suitable for end users. |
| [].btCodes | string[] | EN 16931 Business Term codes the rule references, e.g. ["BT-27"]. |
| [].fields | string[] | Dotted JSON paths the finding maps to, e.g. ["seller.name"]. Use them to highlight the exact form input that failed. |
| [].raw | string | Verbatim technical validator output, e.g. "[BR-01] EN16931: An invoice shall have a specification identifier (at /*:CrossIndustryInvoice...)." |
| Compliance report (always present) | ||
| report | object[] | One row per EN 16931 Business Term found on the invoice, with its value and a pass/fail flag. null if the report could not be built. |
| report[].code | string | Business Term code, e.g. BT-1. |
| report[].name | string | Human-readable term name, e.g. Invoice number. |
| report[].section | string | Grouping for display: header, seller, buyer, lines, payment, totals, or tax. |
| report[].path | string | Dotted JSON path to the field, e.g. lines[0].priceDetails.netPrice. |
| report[].value | string? | Current value of the term, or null when absent. |
| report[].isValid | boolean | false when a validation error references this term, otherwise true. |
| report[].errors | string[] | All friendly error messages on this term, empty when there are none. |
| report[].warnings | string[] | All friendly warning messages on this term, empty when there are none. |
The French rules change. Your integration does not.
Factur-X is a moving target. FNFE-MPE and CEN revise the per-profile XSD schemas, the EN 16931 Schematron rule sets, and the French BR-FR constraints, and the e-invoicing reform itself phases in (reception of e-invoices becomes mandatory for all companies in September 2026, with issuance phased across 2026 and 2027). Teams that self-host an open-source validator (Mustang, the KoSIT validator) own the burden of tracking every release, upgrading the library, re-testing, and redeploying before each effective date. Miss one, and your integration silently keeps validating against last year's rules.
InvoiceXML carries that burden for you. When a new artifact set is published, we ship it and switch POST /v1/validate/facturx to the updated rules on the standard's official effective date, automatically. No tracking FNFE-MPE, no monitoring CEN, no library upgrade, no redeploy on your side: the same endpoint is always validating against the currently-effective French rules. That removes an estimated 0.3 to 0.5 FTE of ongoing compliance-maintenance work and eliminates the risk of an integration falling out of compliance the day the rules change.
Integrate Factur-X validation into your workflow
REST API
Call POST /v1/validate/facturx from any language. Returns structured JSON in under 2 seconds. Use the valid boolean to gate transmission to your PDP or Chorus Pro, only forward invoices that pass.
API docsZapier / Make / n8n
Add a validation step to your no-code invoice workflow before a Factur-X file leaves your accounting tool. On validation failure, route the errors[].message values to Slack, email, or your helpdesk.
Automation integrationsCI/CD Pipeline
Validate your Factur-X generation output on every build. The API returns a non-zero errorCount for non-compliant output, making it straightforward to fail a build step if generated invoices would be rejected by a PDP.
View cURL exampleSkip the API. Use getfacturx.com
Our online companion tool. Create and validate Factur-X invoices in your browser, no integration, no API key, no code. Perfect for freelancers, small businesses, and one-off invoices.
Complete Factur-X Toolkit
Everything you need to create, convert, validate, and extract Factur-X invoices via REST API or online.
Why Factur-X Validation Matters for the French E-Invoicing Reform
The French e-invoicing reform reshapes how every company doing business in France sends and receives invoices. From September 2026 all companies must be able to receive electronic invoices, with the obligation to issue them phasing in across 2026 and 2027 by company size. Invoices no longer travel directly between trading partners: they flow through a Plateforme de Dematerialisation Partenaire (PDP), while Chorus Pro remains the public-sector (B2G) portal. A Factur-X file is more than a PDF; it is a hybrid PDF/A-3 container that must align across three layers: the visual PDF, the embedded Cross Industry Invoice (CII) XML, and the PDF/A-3 archival metadata.
Our Factur-X Validation API is the deterministic gatekeeper for that pipeline. By running the EN 16931 and FNFE-MPE rule checks a PDP applies at intake, before you transmit, you catch a non-compliant document in your own system rather than receiving a rejection lifecycle status from the platform. Factur-X is the French branding of the same format as the German ZUGFeRD standard, so the equivalence is exact: a file that passes here is accepted on both sides of the Franco-German corridor without re-encoding.
Comprehensive Schematron, XSD, and BR-FR Checks
Unlike a plain XML parser, the InvoiceXML engine performs layered validation: the UN/CEFACT CII D16B schema for structural integrity, over 200 EN 16931 Schematron business rules, and the French BR-FR constraints specific to Factur-X. These rules catch the most common reasons a PDP or Chorus Pro rejects an invoice, such as:
- Mathematical discrepancies in VAT breakdowns and total amounts (BR-CO-12, BR-CO-14).
- A missing seller VAT identifier or French SIREN/SIRET legal identifier on a B2B invoice (BR-FR rules).
- Profile-scope violations, ensuring a MINIMUM or BASIC WL file is not transmitted where a complete invoice is required.
Compliance That Stays Current Without Your Intervention
A RESTful validation step lets your ERP or accounting software gate every Factur-X file automatically, reducing manual auditing and eliminating silent failures where an invoice looks correct to the eye but fails machine-readable validation. Crucially, InvoiceXML maintains the standards artifacts for you: when FNFE-MPE or CEN publishes a new schema, rule set, or profile revision, we switch the endpoint to it on the official effective date. Your integration keeps calling the same URL and is always validating against the currently-effective French rules, with no library upgrades, redeploys, or regulatory tracking on your side.
Frequently Asked Questions
Which Factur-X profiles does the API validate?
The API validates all five Factur-X profiles defined by FNFE-MPE: MINIMUM, BASIC WL, BASIC, EN 16931, and EXTENDED. The declared profile is detected automatically from the XML SpecificationIdentifier and the corresponding XSD schema and Schematron rules are applied. Because Factur-X is the French branding of the same hybrid PDF/A-3 plus CII format as ZUGFeRD, a valid Factur-X file is by construction a valid ZUGFeRD file.
Will a file that passes here be accepted by Chorus Pro and my PDP?
The API runs the same EN 16931 and Factur-X rule checks a Plateforme de Dematerialisation Partenaire (PDP) and Chorus Pro apply at intake, so a file that returns valid: true clears the structural and business-rule gate those platforms enforce. An entry in errors is a blocking violation those platforms will reject. An entry in warnings is advisory, such as the PROFILE-SCOPE note on MINIMUM and BASIC WL documents, and does not block compliance. Every finding carries a layer field telling you whether it came from the XSD, the EN 16931 base rules, or the Factur-X profile rule set.
What is the relationship between Factur-X and ZUGFeRD?
Factur-X (France) and ZUGFeRD (Germany) are the same technical format under two national brands: a PDF/A-3 with embedded CII XML, the same five profiles, and the same EN 16931 semantic core. FNFE-MPE and the German FeRD maintain them jointly. In practice that means one file is valid in both countries, and this API validates either name. It accepts the factur-x.xml, zugferd-invoice.xml, and xrechnung.xml attachment names so you do not have to special-case the origin.
Who maintains the rules, and what happens when FNFE-MPE publishes a new version?
InvoiceXML maintains the Factur-X validation artifacts. When FNFE-MPE or CEN publishes a new XSD schema, Schematron rule set, or profile revision, we ship the updated artifacts and switch validation to them on the standard's official effective date, automatically. You make zero changes: no tracking FNFE-MPE releases, no monitoring CEN, no library upgrades, no redeploys. Your integration keeps calling POST /v1/validate/facturx and is always validating against the currently-effective French rules. This is the core difference versus a self-hosted open-source validator you would have to keep updated yourself.
Does validation check the PDF/A-3 layer or only the XML?
The validation targets the embedded CII XML, which is what the business rules apply to: the PDF container is parsed, the embedded invoice attachment (factur-x.xml, zugferd-invoice.xml or xrechnung.xml) is extracted, and the XML is validated against its declared profile rules. Full PDF/A-3 container conformance (fonts, colour profiles, XMP) is not part of this check, so pair the API with a PDF/A validator if your platform also enforces the container level. If the embedded attachment turns out to be UBL instead of CII, the API returns a clear PDF-EMBED-SYNTAX finding instead of a cryptic schema error.
Ready to automate your invoices?
Validate, convert and embed compliant e-invoices through one API. Start your 30-day free trial. No credit card required.