Guide for developers
French e-invoices from code, now the reform is in force.
Since 1 September 2026 every French business has to be able to receive electronic invoices, and large and mid-sized ones have to issue them. This page is for the people writing the software: what the document has to contain, which formats count, where your code stops and the approved platform takes over, and real calls that build and check an EN 16931 invoice from code or from an agent.
Looking for the calendar and the obligations themselves rather than the implementation? That is our guide to the French mandate. Every fact about the reform below was read on impots.gouv.fr or legifrance.gouv.fr on 2026-10-01 and is cited where it is used.
Where your code stops and the platform starts
The reform splits the work in two, and the split decides what you build. Companies subject to the issuing obligation send their invoices to business customers through an approved platform, which delivers them to the platform the customer chose. (DGFiP, Foire aux questions, Je découvre la facturation électronique (version of 01/09/2026)) The issuer's platform also extracts the invoice data the tax administration needs and transmits it. (DGFiP, Foire aux questions, Je découvre la facturation électronique (version of 01/09/2026))
| Your software | The approved platform |
|---|---|
| Holds the invoice data and gets every mandatory field right | Issues, transmits and receives the electronic invoice |
| Produces the document in UBL, CII or Factur-X, or hands the data to a tool that does | Extracts the invoice data the administration collects and sends it |
| Reads what suppliers send back into your books | Carries the lifecycle statuses, refusals and disputes |
| Is connected to at least one approved platform | Sends e-reporting of transaction and payment data |
That last row on the left is not optional. Invoicing software counts as a "solution compatible" only under two cumulative conditions: it offers features compatible with the reform, and it is connected to at least one approved platform. (DGFiP, Foire aux questions, Je découvre la facturation électronique (version of 01/09/2026)) The DGFiP calls a provider of such software an opérateur de dématérialisation, and is explicit that it is not registered by the tax administration and has to go through an approved platform to transmit anything. (DGFiP, Facturation électronique, fiche 1 (2025)) The registered platforms are listed on impots.gouv.fr, and that list is the only one that counts.
InvoiceForge is on the left side of that table only. It is not an approved platform, not a PDP and not a Peppol access point, and it transmits nothing to anyone. It generates, validates and reads the document. AgentToolWorks is not affiliated with the DGFiP, the AIFE or AFNOR.
The three formats
The tax administration's own definition: an electronic invoice must "respecter un format donné (UBL, CII ou tout format mixte composé d'un fichier de données structurées et d'un fichier image)", carry the mandatory mentions in dedicated fields, and travel through an approved platform. (impots.gouv.fr, Je découvre la facturation électronique (modified 26/05/2026)) The DGFiP names the three: approved platforms are required to transmit invoices in one of them, CII and UBL being purely structured and Factur-X a mixed format made of a structured XML file and a readable PDF. (DGFiP, Facturation électronique, fiche 1 (2025)) A plain PDF sent electronically is not an electronic invoice. (DGFiP, Foire aux questions, Je découvre la facturation électronique (version of 01/09/2026))
For a developer that reduces to one semantic model and two XML syntaxes. EN 16931 defines the business terms (BT-1 is the invoice number, BT-47 the buyer's legal registration identifier, and so on); UBL 2.1 and CII are two ways of writing them down; Factur-X is the CII payload attached to a PDF. Get the data right once, in the model, and the syntax is a serialisation problem.
The French formats and profiles themselves are specified in the AFNOR standard XP Z12-012, with the API between business systems and platforms in XP Z12-013 and the B2B use cases in XP Z12-014; the administration's external specifications are at version 3.2 of 30 April 2026. (impots.gouv.fr, Spécifications externes et normes (modified 02/07/2026)) If you are writing a serialiser rather than calling one, those are the documents to read, not a summary.
What InvoiceForge covers of this, precisely: it generates UBL 2.1 (EN 16931 or Peppol BIS Billing 3.0 identifiers), and it reads UBL 2.1 and CII, the XML inside a Factur-X file. It does not produce CII, does not build the Factur-X PDF wrapper, and does not apply the French national rules on top of the European base. The describe_coverage tool says the same thing in its answer, so an agent can read the limits before relying on the output.
The data the administration reads from your invoice
The administration does not collect every mention on an invoice, only the data it needs, notably to pre-fill VAT returns: 26 mandatory data points in 2026, then 34 from 2027. (DGFiP, Foire aux questions, Je découvre la facturation électronique (version of 01/09/2026)) The DGFiP publishes the list with the business term each one maps to, which is the table a developer actually needs. (DGFiP, data to transmit and their correspondence in the data flow (updated August 2026)) The first three columns below are theirs. The last one is what InvoiceForge does with that term today, read off our own code rather than our marketing.
On every invoice
| From | Data | Business term | InvoiceForge today |
|---|---|---|---|
| 2026 | Supplier SIREN | BT-30 | seller.legalId |
| 2026 | Supplier country | BT-40 | seller.countryCode (checked, BR-CL-14) |
| 2026 | Customer SIREN | BT-47 | buyer.legalId (written when given, not enforced) |
| 2026 | Customer country | BT-55 | buyer.countryCode (checked) |
| 2026 | Category of the operation: goods, services or both | BT-23 | Not modelled yet |
| 2026 | Issue date | BT-2 | issueDate (checked) |
| 2026 | Invoice number | BT-1 | invoiceNumber (checked) |
| 2026 | Taxable amount per VAT rate | BT-116 | Computed |
| 2026 | VAT amount per rate | BT-117 | Computed |
| 2026 | VAT rate | BT-119 | From each line's vatRate |
| 2026 | Total without VAT | BT-109 | Computed |
| 2026 | Total VAT | BT-110 | Computed |
| 2026 | Currency | BT-5 | currency (checked) |
| 2027 | Item name (per line) | BT-153 | lines[].name (checked) |
| 2027 | Quantity (per line) | BT-129 | lines[].quantity (checked) |
| 2027 | Unit price without VAT (per line) | BT-146 + BT-147 + BT-148 | BT-146 only (lines[].unitPrice) |
On some invoices, depending on the operation
| From | Data | Business term | InvoiceForge today |
|---|---|---|---|
| 2026 | Supplier and customer intra-community VAT numbers | BT-31, BT-48 | seller.vatId, buyer.vatId |
| 2026 | Number of the invoice being corrected | BT-25 | Not modelled yet |
| 2026 | Option to pay VAT on debits | BT-8 | Not modelled yet |
| 2026 | Exemption reason, including the franchise en base | BT-120 | vatExemptions[] (checked, BR-E-10 and friends) |
| 2026 | Self-billing | BT-3 | typeCode (code list checked) |
| 2026 | Reverse charge | BT-118, code AE | lines[].vatCategory AE (checked) |
| 2026 | Delivery or completion date, if different | BT-72 | Not modelled yet |
| 2026 | Single VAT group member, special margin schemes | BT-21/BT-22, BT-120 | Notes not modelled; BT-120 yes |
| 2027 | Discounts and charges, delivery address, early payment discount | BT-92 to BT-103, BT-75 to BT-80 | Not modelled yet |
6rows say "not modelled yet", and the one that matters most is BT-23, the category of the operation, which is required on every invoice from 2026. The DGFiP maps it to the business process type, with its own code list. (DGFiP, data to transmit and their correspondence in the data flow (updated August 2026)) Until we model it, a document from generate_invoice is a correct EN 16931 base that your pipeline or your platform has to complete for France. We would rather print that in a table than have you discover it from a rejection.
The same 1 September 2026 date made four mentions newly mandatory on French invoices: the customer's SIREN, the category of the operation, the option to pay VAT on debits when it applies, and the delivery address when it differs from the billing address. (DGFiP, Foire aux questions, Je découvre la facturation électronique (version of 01/09/2026)) They come from Décret n° 2022-1299 of 7 October 2022, which amended article 242 nonies A of annex II to the CGI. (Légifrance, Décret n° 2022-1299 du 7 octobre 2022)
Generating and checking an invoice: real calls
Four calls to the production endpoint, made on 2026-10-01. The requests are shown as the params of an MCP tools/call, which is also what an agent sends. The parties are fictional and their identifiers are placeholders. Where a response was shortened, the note under it says what was cut.
1. Validate the data before building anything
validate_invoice (1 credit) accepts incomplete and malformed data on purpose, because that is what you want checked. This export has two mistakes that are common in real ones: a three-letter country code and a standard-rated line with a zero rate.
{
"name": "validate_invoice",
"arguments": {
"invoice": {
"invoiceNumber": "F-2026-0412",
"issueDate": "2026-10-01",
"currency": "EUR",
"seller": { "name": "Atelier Exemple SAS", "vatId": "FR00123456789",
"legalId": "123456789", "city": "Lyon", "countryCode": "FRA" },
"buyer": { "name": "Client Exemple SARL", "legalId": "987654321",
"city": "Paris", "countryCode": "FR" },
"lines": [{ "id": "1", "name": "Integration work, September",
"quantity": 10, "unitPrice": 650, "netAmount": 6500,
"vatCategory": "S", "vatRate": 0 }]
}
}
}{
"valid": false,
"rulesChecked": 41,
"violations": [
{ "rule": "BR-CL-14", "term": "BT-40", "severity": "error",
"message": "Seller country must be ISO 3166-1 alpha-2, got 'FRA'." },
{ "rule": "BR-S-05", "term": "BT-152", "severity": "error",
"message": "line 1: a standard rated line must carry a VAT rate above zero." }
],
"coverage": "Actively checks 39 rule groups from EN 16931 and Peppol BIS Billing 3.0, plus 2 check of our own marked ATW-. ...",
"unknownFields": []
}Trimmed: the coverage sentence is cut after its first clause; nothing else was removed. The call took 1.6 s from our machine.
Each violation names the rule and the business term, so the fix goes into the mapping that produced the field, not into one invoice. The BR-CL-14 and BR-S-05 guides explain what makes each one fire.
2. Generate the UBL document
generate_invoice (1 credit) takes the corrected data, computes every total and the VAT breakdown per rate, validates, and only then returns the XML. It refuses to return a document that breaks a rule it checks.
{
"name": "generate_invoice",
"arguments": {
"profile": "en16931",
"invoice": {
"invoiceNumber": "F-2026-0412",
"issueDate": "2026-10-01",
"dueDate": "2026-10-31",
"currency": "EUR",
"seller": { "name": "Atelier Exemple SAS", "vatId": "FR00123456789",
"legalId": "123456789", "addressLine": "1 rue Exemple",
"city": "Lyon", "postalCode": "69001", "countryCode": "FR" },
"buyer": { "name": "Client Exemple SARL", "vatId": "FR00987654321",
"legalId": "987654321", "addressLine": "2 avenue Exemple",
"city": "Paris", "postalCode": "75002", "countryCode": "FR" },
"lines": [
{ "id": "1", "name": "Integration work, September", "quantity": 10,
"unitPrice": 650, "netAmount": 6500, "vatCategory": "S", "vatRate": 20 },
{ "id": "2", "name": "Technical book", "quantity": 2,
"unitPrice": 42.5, "netAmount": 85, "vatCategory": "S", "vatRate": 5.5 }
],
"paymentTerms": "30 days end of month"
}
}
}{
"format": "ubl",
"profile": "en16931",
"specification": "urn:cen.eu:en16931:2017",
"totals": {
"lineExtensionAmount": 6585,
"taxExclusiveAmount": 6585,
"taxAmount": 1304.68,
"taxInclusiveAmount": 7889.68,
"payableAmount": 7889.68,
"vatBreakdown": [
{ "category": "S", "rate": 20, "taxable": 6500, "tax": 1300 },
{ "category": "S", "rate": 5.5, "taxable": 85, "tax": 4.68 }
]
},
"warnings": [],
"xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Invoice ..."
}Trimmed: the xml string (4,566 characters) is cut after its first element; an excerpt follows. The call took 0.9 s.
<cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
<cbc:ID>F-2026-0412</cbc:ID>
<cbc:IssueDate>2026-10-01</cbc:IssueDate>
...
<cac:PartyLegalEntity>
<cbc:RegistrationName>Client Exemple SARL</cbc:RegistrationName>
<cbc:CompanyID>987654321</cbc:CompanyID>
</cac:PartyLegalEntity>
...
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">85.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">4.68</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.50</cbc:Percent>
<cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
...
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">6585.00</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">6585.00</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">7889.68</cbc:TaxInclusiveAmount>
<cbc:PayableAmount currencyID="EUR">7889.68</cbc:PayableAmount>
</cac:LegalMonetaryTotal>Two details worth noticing. The book line at 5.5 percent comes to 4.675 of VAT, written as 4.68: amounts are rounded to the cent per rate, and the totals are then summed from the rounded values, which is how they have to reconcile. And the buyer's SIREN went in as buyer.legalId and came out in PartyLegalEntity/CompanyID, the UBL home of BT-47.
3. The call that passes and should not
Same invoice, buyer SIREN removed. Under EN 16931 that identifier is optional, so the European rules have nothing to say.
{
"name": "validate_invoice",
"arguments": {
"invoice": {
"invoiceNumber": "F-2026-0413",
"issueDate": "2026-10-01",
"currency": "EUR",
"seller": { "name": "Atelier Exemple SAS", "vatId": "FR00123456789",
"legalId": "123456789", "addressLine": "1 rue Exemple",
"city": "Lyon", "postalCode": "69001", "countryCode": "FR" },
"buyer": { "name": "Client Exemple SARL", "addressLine": "2 avenue Exemple",
"city": "Paris", "postalCode": "75002", "countryCode": "FR" },
"lines": [{ "id": "1", "name": "Integration work, September",
"quantity": 10, "unitPrice": 650, "netAmount": 6500,
"vatCategory": "S", "vatRate": 20 }]
}
}
}{
"valid": true,
"rulesChecked": 41,
"violations": [],
"coverage": "... This is a documented subset of the norm (roughly 150 rules plus national CIUS rules); passing here means no checked rule was broken, not that a tax authority will accept the document.",
"unknownFields": []
}Trimmed: the coverage sentence is cut before its last clause, which is quoted in full. The call took 1.3 s.
valid: true, and correctly so for what the tool checks. But the customer's SIREN is one of the data points on every French invoice from 2026. (DGFiP, data to transmit and their correspondence in the data flow (updated August 2026)) This is the difference between a European validator and a French one, and it is why the response carries its own coverage statement instead of a bare green tick. Until the French rules are modelled here, check the French-only fields yourself before you hand the document on: BT-30 and BT-47 present for a domestic B2B invoice, BT-23 set.
4. Read what a supplier sends you
Receiving is the half every French business has had to handle since 1 September 2026, whatever its size. (DGFiP, Foire aux questions, Je découvre la facturation électronique (version of 01/09/2026)) extract_invoice (1 credit) reads an incoming UBL or CII document into the same JSON shape the other tools take, and lists any field the document did not contain rather than guessing it. For a Factur-X file, pass the XML attached inside the PDF.
{
"name": "extract_invoice",
"arguments": {
"xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rsm:CrossIndustryInvoice ...>..."
}
}{
"invoice": {
"invoiceNumber": "FA-88231",
"issueDate": "2026-09-15",
"dueDate": "2026-10-15",
"typeCode": "380",
"currency": "EUR",
"buyerReference": "PO-2026-117",
"seller": {
"name": "Fournisseur Exemple SA", "vatId": "FR00111222333",
"legalId": "111222333", "addressLine": "3 quai Exemple",
"city": "Bordeaux", "postalCode": "33000", "countryCode": "FR"
},
"buyer": {
"name": "Atelier Exemple SAS", "legalId": "123456789",
"city": "Lyon", "postalCode": "69001", "countryCode": "FR"
},
"lines": [
{ "id": "1", "name": "Office chairs", "quantity": 4, "unitCode": "C62",
"unitPrice": 120, "netAmount": 480, "vatCategory": "S", "vatRate": 20 },
{ "id": "2", "name": "Installation, reverse charge", "quantity": 3,
"unitCode": "HUR", "unitPrice": 65, "netAmount": 195,
"vatCategory": "AE", "vatRate": 0 }
]
},
"syntax": "cii",
"missing": []
}Trimmed: the request's xml string (a 6,044-character CII document) is cut after its root element. The response is complete, only re-wrapped. The call took 2.0 s.
The document read here has a reverse charge line, which comes back as category AE at a zero rate rather than being flattened to standard VAT. Book it from this shape, or feed it straight into validate_invoice to check what a supplier sent before you accept it.
Disclosure: the first time we ran this call for this page, the server read the CII document wrongly (the invoice number came back as the guideline identifier and the seller as the first line item). We fixed the extractor, added the same document to the production test suite, and captured the response above from the corrected server.
From an agent
The same four tools are a remote MCP server, so an agent that drafts invoices from timesheets, or one that reads a supplier inbox, can call them mid-task without any glue code. A realistic loop: build the invoice data, call validate_invoice, fix what it names, call generate_invoice, hand the XML to your approved platform's API. describe_coverage (0.2 credit) lets the agent read the limits first, and get_usage is free.
https://invoiceforge.agenttoolworks.com/mcp
claude mcp add --transport http invoiceforge \ https://invoiceforge.agenttoolworks.com/mcp \ --header "Authorization: Bearer atw_live_your_key"
100 free credits at signup, no card. Plain HTTP works too: the requests above are the body of a JSON-RPC tools/call, as shown on the docs page.
Questions developers ask
- Which file formats does the French reform accept?
- Three: UBL, CII, and Factur-X, a mixed format made of a structured XML file and a readable PDF. The DGFiP states that approved platforms are required to transmit invoices in one of these three. A plain PDF sent by email is not an electronic invoice under the reform.
- Can my software send e-invoices directly to my customer's approved platform?
- Not on its own. Companies subject to the issuing obligation send invoices through an approved platform, which delivers them to the platform chosen by the customer. Invoicing software qualifies as a compatible solution only if it offers features compatible with the reform and is connected to at least one approved platform.
- Who sends invoice data to the tax administration?
- The issuer's approved platform. It extracts the invoice data the administration needs and transmits it. Your job is to make sure that data is in the invoice, in the right field.
- Is InvoiceForge an approved platform?
- No. It is not an approved platform, not a PDP and not a Peppol access point, and it transmits nothing. It generates UBL invoices, validates invoice data against a documented subset of the EN 16931 rules, and reads incoming UBL and CII into JSON. You still need an approved platform to exchange invoices in France.
- Does passing an EN 16931 validator mean the invoice is valid for France?
- No. EN 16931 is the European base. The French reform adds data of its own, such as the customer's SIREN and the category of the operation, and the formats and profiles are specified in the AFNOR standard XP Z12-012. An invoice can pass every base rule and still miss a French requirement, which is exactly what one of the calls on this page shows.
Sources
Read on 2026-10-01. Reform calendars and specifications move; if you read this much later, check the source before acting on it.
- impots.gouv.fr, Je découvre la facturation électronique (modified 26/05/2026)
- DGFiP, Foire aux questions, Je découvre la facturation électronique (version of 01/09/2026)
- DGFiP, Facturation électronique, fiche 1 (2025)
- DGFiP, data to transmit and their correspondence in the data flow (updated August 2026)
- impots.gouv.fr, Spécifications externes et normes (modified 02/07/2026)
- Légifrance, Décret n° 2022-1299 du 7 octobre 2022
- impots.gouv.fr, list of approved platforms