Description
The deadline that arrives first is not the one you think.
From 1 September 2026 every French business — yours included, whatever its size — must be able to receive an electronic invoice. Not issue one. Receive one. Your suppliers switch on that date, and a supplier whose invoice you cannot take delivery of is a supplier you are about to have a problem with.
Thirty seconds of the plugin at work, on a real shop:
You have probably looked into this already. The usual answer is an accounting platform: a second back-office at €30 a month, with its own login and its own vocabulary, where your invoices live on one side of a wall and your orders on the other. Or you asked your accountant, who said it was in hand. Neither told you what you have to do, or by when.
So: you run a WooCommerce shop, you want to be in order before September, and what stands in your way is that nobody has told you plainly what “in order” means. If that is where you are, this is what the plugin does about it.
Receive. Drop the file your supplier sent you onto one screen. Its number, the supplier, their SIRET, the dates, the VAT and the total are read out of the file itself. Nothing is typed, and the same invoice sent twice is refused instead of paid twice. Today that is a folder of PDFs and a spreadsheet you retype them into, with no way to tell an electronic invoice from an ordinary one until February.
Issue. Every order that completes produces its own invoice, in the format the reform requires: a PDF you can read with the machine-readable data sealed inside it, carrying the mentions French law demands, numbered without gaps.
Declare. Your sales to private customers are totalled period by period and filed on the tax calendar — amounts and VAT rates only, never a customer, never an invoice number. Your business invoices travel to your approved platform instead, and you watch them go.
Your shop talks to the tax authority, without leaving WordPress.
Then comes your turn. From 1 September 2027 you have to issue your invoices to business customers electronically, through an approved platform, and report your consumer sales on a schedule. Miss it and it is €15 for each invoice not issued in electronic form and €250 for each e-reporting transmission not made, each capped at €15,000 a year.
And the part that costs nothing to start. No account to create, no subscription to another service, no stock to configure, nothing to change in how you already work. Fill in your business details once and the next completed order produces its own compliant invoice. A rehearsal platform ships with the plugin, so the whole chain can be exercised before you sign up anywhere.
If you sell to the public sector, you are already late. Invoicing a town hall, a school or a hospital has been electronic-only for years, and it goes through Chorus Pro. That connection is in the free version, with the whole transmission chain behind it — the queue, the lifecycle statuses, and the trail on each order — because a shop that is already out of compliance should not have to wait for a licence to stop being so.
What the free version does
- Receive your suppliers’ electronic invoices: drop the file, everything is read out of it, duplicates refused, CSV export for your accountant
- Factur-X invoices: a PDF/A-3 you can read with the EN 16931 XML embedded inside it, produced automatically when an order completes
- The legal mentions a French invoice needs: SIREN, SIRET, VAT number, late payment penalties, the €40 recovery indemnity, article 293 B for shops under the franchise en base
- Sequential, gap-free numbering that never restarts
- SIRET, VAT number and order reference at checkout, on both the classic and the block checkout, with real validation — a SIRET carries a checksum, and a French VAT key is derived from the SIREN
- Credit notes on refund, with their own series and a reference back to the invoice they correct, as the standard requires
- Transmission to Chorus Pro for your public sector customers, with the statuses the reform defines and the whole trail on the order
- Invoices attached to the WooCommerce emails you choose, and a documents screen you can search, filter by month and export as a ZIP
Pro is on the way, for when 2027 comes for you
Everything above is in the free version and stays there. A paid version is being built for the second half of the reform — the part that starts in September 2027 — and it is not on sale yet. What it will add:
- Your own approved platform rather than only Chorus Pro: a connector that speaks to any platform with a REST API, so whichever of the hundred-odd approved ones you or your accountant have chosen, the plugin hands it your invoices — you paste the address and the token they gave you, and nothing else changes
- Automatic e-reporting of your consumer sales, filed on the tax calendar, with the date and the receipt your platform hands back
- A compliance dashboard: where every document stands, which ones are stuck, and why
- Payment reminders, counted from the due date, in an email that wears your shop’s own header and footer
- Your suppliers’ invoices collected from a mailbox by themselves, instead of being dropped on the screen one at a time
- Delivery notes: the sheet that goes in the parcel, with or without prices
None of that is needed before 2027, which is why the free version is the whole answer to the 2026 date. Follow earnestlabs.io to be told when Pro lands.
What the plugin cannot check for you. It sends your documents to the address you enter. It cannot tell whether that address belongs to a platform the tax administration has registered — the official list is published on impots.gouv.fr, and no plugin can match an endpoint to it. Check yours against that list, ask it to confirm in writing that it accepts Factur-X, and use the connection test before you switch transmission on.
Outside France? The plugin still produces valid Factur-X invoices — the format is European. The French tax features simply stay dormant.
External services
This plugin can connect to Chorus Pro, the French State’s invoicing portal, through PISTE, the State’s API gateway. That connection is how an invoice reaches a public sector customer — a town hall, a school, a hospital — which French law has required to be electronic for years.
Nothing is sent unless you set it up. Transmission is off by default, and the plugin ships with a rehearsal platform that replays the whole chain locally without contacting anything. A shop that never enters credentials never reaches either service.
When it happens. Once you have entered your own PISTE credentials and your Chorus Pro technical account in Settings Approved platform and switched transmission on, three things reach out: an order carrying a SIRET that completes sends its invoice; the plugin then asks periodically for the status of invoices it has already sent, so each order can show where it stands; and the “Test the connection” button knocks once when you press it.
What is sent. The invoice itself — a Factur-X file holding your business details, your customer’s name, address and SIRET, the invoice number and dates, the lines, the amounts and the VAT. Your credentials travel with each call to authenticate it. Nothing else leaves your site, and orders without a SIRET are never sent.
Which addresses. oauth.piste.gouv.fr and api.piste.gouv.fr in production, sandbox-oauth.piste.gouv.fr and sandbox-api.piste.gouv.fr while you are testing.
Both services are operated by the French State. PISTE terms of use, whose section 9 covers personal data and cookies: https://piste.gouv.fr/cgu — Chorus Pro community and documentation: https://communaute.chorus-pro.gouv.fr/
Screenshots





FAQ
I do not have time to deal with this right now.
Then start with the half that has a date on it. Receiving is free, it takes filling in your business details once, and it is the only thing required of you on 1 September 2026. Issuing and declaring are 2027 — a year away. You are not choosing between everything and nothing.
I do not have the budget.
Receiving supplier invoices, issuing compliant Factur-X invoices, the French legal mentions, gap-free numbering, credit notes and Chorus Pro for the public sector are all in the free version, for good. There is nothing to buy today: the paid version is being built for 2027, for shops that have to reach an approved platform of their own.
It is not up to me, my accountant handles the invoices.
Your accountant files your returns; the reform is about how a document leaves your shop and reaches your customer. That part happens where the order is, which is here. Nothing changes in what you send your accountant — and the documents screen exports a month as a ZIP for them.
I have already tried a plugin like this.
Most invoice plugins produce a PDF and stop there. The reform is not about the PDF: it is about the structured data inside it, the platform it travels through, and the totals filed on a schedule. If what you tried did not mention an approved platform or e-reporting, it was solving the older problem.
Is this for a shop my size?
The obligation makes no exception for size — a one-person business is subject to the same dates as a group. What changes with size is the volume, not the rule. If you invoice at all, this is for you.
I am not sure I am ready.
Nobody is asking you to be. The date is 1 September 2026 and it does not move. What you can do today is install the free version, drop one supplier invoice on it, and see what happens — it costs a click and it is reversible.
Do I need an approved platform?
To issue invoices to business customers from 2027, yes — French law requires every business to have one, and the plugin will connect to yours rather than replace it; that connector is the paid version, which is being built and arrives well before the date. To sell to the public sector, no: Chorus Pro is the State’s own portal, it is free, and the connection to it is in the free version today.
Can I try transmission without sending anything real?
Yes. A rehearsal platform ships with the plugin and replays the entire chain — queue, send, statuses, trail — without a single byte leaving your server.
Does the plugin do my accounting?
No. It issues and receives compliant documents and sends them where the law says they must go. Your accounting stays with your accountant.
Will it work with my theme?
The invoice is generated as a PDF by the plugin itself, so it does not depend on your theme at all.
Does it work with HPOS?
Yes, the plugin declares compatibility with WooCommerce’s high performance order storage.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“EarnestLabs FactureFlux for WooCommerce” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “EarnestLabs FactureFlux for WooCommerce” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
0.6.21
- Payment reminders, automatic mailbox collection and delivery notes move to Pro. None of the three is required by the 1 September 2026 obligation: receiving an invoice stays free, by dropping the file on a screen. Having it collected for you, chasing what you are owed and printing a sheet for a parcel save time and recover money, which is a different thing. Moved now, while the plugin is still in review and nobody has installed it, because moving one later means taking it away from someone.
- The accent colour and the footer line move from the Delivery notes panel to Invoices, where they belonged: they print on every invoice, and a free shop keeps its own colours.
- The Help screen pointed at a support forum and a review page under the old slug, and at a pricing anchor that does not exist. Three dead links on the one screen a shop opens when something is already wrong.
0.6.20
- One platform left the picker. Its provider sells to software editors, not to shops — a floor of ten thousand documents a month — so no shop could have subscribed to it, and a name nobody can sign up to only wastes the one minute a shop spends choosing. What stands in its place is the connector that takes an address and a token, whichever platform gave them to you.
- The plugin no longer names platforms it has ready-made connectors for. It names what it does: you paste the address and the token your platform gave you, and the invoices leave through it.
- Said plainly on the platform screen: the plugin cannot check that a platform is accredited. Nothing public exposes that, and a plugin that implied otherwise would be putting its own word behind a fact it cannot verify.
0.6.19
- A payment reminder offered a “pay online” link that refused the customer. The link was written into every reminder, but the page behind it only accepts an order awaiting payment: on an order on hold it landed her on “this order cannot be completed, please contact us”. Chasing someone for money with a button that turns her away is worse than offering nothing. The link now appears only when the payment would actually be accepted, and the transfer details above remain the way to pay.
- The order screen pointed at its own answer. When a shop had typed an exchange rate by hand, the hint underneath read “this site already answers 0.85, fill this in only to override it” — while 0.85 sat in the box just above, put there by that same shop. The screen now asks what the site would answer if the field were empty, so the sentence is either “nothing here knows it, and here is why it matters” or a genuine rate coming from a multi-currency plugin.
- Every action the administration triggers answered a signed-out caller with a blank page. They are all registered for signed-in callers only, so a signed-out request matched no handler at all and WordPress ended on an error page with no error in it — a white box titled “WordPress > Error”. Found while checking that a document URL refuses a stranger: it refused, and said nothing, which reads like a broken site rather than a locked door. All twenty-one now answer 403 with a sentence and a link to sign in, and the list is read from what is actually registered rather than written out by hand.
- Filtering a list sent the eye back to the top of the page. The table reloads without a page load, and what it scrolled to afterwards was the whole screen — so pressing Filter landed you on the banners above, with nothing to do with what you had just asked. Twice reported, on two screens. It now brings the RESULT into view, which sits above the filters and carries them along, and it does not move the page at all when that line is already visible.
- An identifier at a platform meant nothing outside the platform that issued it, and nothing recorded which one that was. Change provider — an ordinary event after September 2026, and one that also happens when a platform loses its registration — and every past document announced its number under a provider that had never heard of it, while the hourly sweep asked the NEW platform about the OLD one’s reference and wrote the 404s into the trail as though the document had gone wrong. Seen on a real screen: two identifiers issued by one platform, announced under another. The issuing platform is now recorded beside the number, the panel names it, and nothing is asked of a platform that did not hand it over. Documents filed before this records nothing about their issuer, and are left exactly as they were rather than given an invented one.
- The person at a company appeared nowhere on her own invoice. As soon as a billing company was filled in, it took the customer name — which is right, the company is what owes — and the person vanished: not on the printed page, not in the XML, and the document had no field for her at all. EN 16931 has one, BT-56, the buyer contact point. She is now named on the page under the company, and written into the XML as DefinedTradeContact, at the one position the CII sequence allows. Validated against the official rules on a real document.
- The buyer’s e-mail is on the printed page too. It already travelled in the XML as BT-49, the address the network routes by; on paper it is the one line that lets someone chase a payment or query a line without going back to the shop’s records. Not repeated when the address IS the customer name.
-
An order keyed in without a street left two empty lines in the middle of the address block. They are printed only when there is something to print.
-
Creating an invoice by hand said nothing, either way. On success the button redirected with a flag nothing read: the document was written and the screen came back silent, so the only way to know the click had worked was to hunt for the panel and see it had changed. On refusal it sent another flag nothing read either — clicking “Create the invoice” on an order with no customer at all did nothing, said nothing, and left no way to learn why. Both now use the message bus the rest of that panel already used.
- The refusal on the order screen was written inside a closed drawer. The SIRET field lives in the billing block WooCommerce keeps folded until the pencil is clicked, so a company saved without a SIRET was blocked — correctly — and the explanation was printed where nobody could see it, with the focus and the scroll doing nothing at all on a hidden field. Reported as “the Update button does not work, and there is no message”. The refusal now appears at the top of the screen, where the hand just clicked, and the billing block opens itself on the field to fill in.
-
The documents list printed a dash where the invoice printed a name. An order carrying nothing but an e-mail address still produces an invoice headed “Billed to name@example.com”, and the customer column showed nothing beside it. The list now names her through the same function the document uses, so the two cannot drift apart whatever is missing.
-
A credit note never left the shop. Nothing listened for it: the invoice went onto the network and the document that UNDOES it stayed on the disk, so the buyer’s software still held a debt that had been cancelled and the correction the tax network needs to see was never sent. Measured on a real preprod: an invoice deposited at 8.50 and its credit note written, filed and never queued. It now goes out on its own, with its own identifier at the platform — one status field cannot hold two documents — and the order panel shows where it stands, under the invoice.
- Saving the settings from a page opened before a platform existed erased that platform’s credentials. The form posted the panel marker without the fields, and an absent field reads as empty: the client ID and the customer ID were blanked, the platform was silently reset to the rehearsal one, and only the secret survived because an empty password already meant “keep what is stored”. The form now declares which platform blocks it carried, and a block it never showed can no longer be cleared by it. Clearing a field on purpose still clears it.
- An unrecognised platform became the rehearsal platform in silence. That is a shop’s invoices quietly rerouted away from a real network. What is stored is kept instead, and the screen says why.
-
What was measured about a platform now dies with the settings that made it true. A red “the platform refused the credentials” stayed on screen after the platform had been changed, and a green “the credentials work” was shown to someone who had tested nothing. Both are thrown away when a platform setting changes.
-
The summary above the received invoices said “VAT 141.48” and “Total 1,294.37” — of what, over what? A figure without its unit is a figure an accountant cannot use. It now reads “47 invoices, deductible VAT 141.48 EUR, total incl. VAT 1,294.37 EUR”, and says how many credit notes were deducted, because a total smaller than the invoices on screen otherwise reads as an arithmetic error.
- Deleting a received invoice asked its question in the browser’s own grey box, which cannot be styled, cannot name the invoice, and looks like the alert of a site trying to trick you — on the one click that erases a legal document. The question is now asked in the page, names the invoice, and says the file goes with it. The link keeps working with no JavaScript at all.
- And it said nothing on the way back. The row vanished and the screen looked exactly as it would have if the click had missed. A confirmation now names the invoice that left.
- The first click on Save could do nothing. The sticky save bar carried no z-index and no background of its own, and wp-admin’s own footer — absolutely positioned at the bottom of the page and later in the document — painted over it and took the click. The bar now owns its stacking context and its ground.
0.6.18
- A credit note now says which invoice it corrects, and an invoice says which credit notes were raised against it. The number was always inside the file — BR-55 puts it there — and was read out of it nowhere. On the received-invoices screen that left a -172.80 line among a dozen others with nothing saying what it undid: a figure that reads as a mistake rather than as a correction. On documents issued the same gap ran the other way — a refunded invoice keeps the total it charged, because an issued invoice is a legal record and is never rewritten, and no line on the screen explained why the books disagreed. Both screens now carry the pair under the number, and clicking it brings the two documents side by side. The invoice PDF is untouched: the mention belongs to the screen, not to a document already issued.
- Received invoices filed before today are gone back over once, and the corrected number read back out of the files they kept. Measured on a real preprod: three credit notes named, none silent, no file unreadable.
- On Windows, no received invoice could be opened again. Saving a post meta value runs it through wp_unslash(), which eats the backslashes of a Windows path, so the stored path led nowhere. Paths are normalised before they are stored. Nothing on a Linux host ever showed this, which is why it lived this long.
0.6.17
- A period could be declared and then quietly grow. A filed period keeps the figures it was filed with, which is right — they are the record of what was transmitted — but the orders underneath keep moving: an order created in the period and paid by transfer after the filing, one keyed in with an earlier date, one imported. The dashboard showed “Declared” with its receipt and looked settled while the money sat undeclared. Found on a real dashboard: August filed at 7,871.83, the same month recounted at 9,580.88 — fourteen sales and 335 EUR of VAT that nothing mentioned. The row now says so, with the count and the amounts. Nothing is re-filed: re-declaring a period is a tax decision, not one for code to take on a shop’s behalf.
- Choosing a platform shows its fields at once. Until now the picker answered a choice with nothing until the page had been saved and reloaded — and a screen that answers a choice with silence is read as broken: you conclude the setting does not work, and never press save. Every platform’s block is now written into the page, all but the chosen one hidden, and the picker reveals the right one on the spot. No request is made — the fields are three inputs and a round trip would be slower than the reveal — and with no JavaScript at all the chosen platform’s block is still the only one on the page, which is where this started.
- A document given up on was told it would be retried. After five failures the queue lets go of an invoice — but the screen kept saying “it would go out on its own within five minutes”, which was true for one more attempt and false for ever afterwards. A sentence that is right for five minutes is worse than one that is plainly wrong: the shop waits instead of acting. Giving up now takes the invoice out of the queue whoever was sending, and the panel says what has actually happened — abandoned after five attempts, out of the queue, and the button is the way to try again.
- A filing that FAILED was freezing its figures as though it had succeeded. The dashboard keeps a declared period exactly as it was transmitted, which is right — but it was doing the same for an attempt that never arrived anywhere, so the row showed the numbers of the failure while the orders underneath had moved on. Measured on a real dashboard: May displayed 66.50 over 2 sales, frozen from a filing that had been refused, while its orders came to 75.00 over 3 — and the shop was one click from filing, reading the wrong figure. Only a period actually transmitted settles now; everything else counts what is there.
- The drift figure is emptied by what makes it wrong, not by a clock. It is cached so the dashboard is not recounted on every load, and the cache expired on a timer — which meant a shop owner could look at the screen and read “2 sales arrived after this declaration” when the third had just arrived. She does not flush caches; she reads what is there and believes it. Saving an order, changing its status or recording a refund now empties the figure for that order period, so the next look is a fresh count and every other look is free.
- A month that sold only to businesses reads 0.00 and looks broken. It is correct — a business sale is declared by its own invoice travelling the network, and counting it here as well would declare it twice — but the row said nothing, and a shop that knows it sold in April concludes the plugin is at fault rather than that the reform counts differently. The row now says so where the doubt appears, and only when there is something to explain.
- The connection test said the key was accepted whatever the platform answered. Anything that was not a 401 or a 403 — a 404, a 500, a gateway error — came back as “the key is accepted”, which asserts more than the answer carries. A 404 on the directory lookup means something useful and quite different: the key got through and the company is not registered yet, so nobody can address an invoice to it until the platform does that. The three cases are now told apart, and the result is repeated at the head of the platform panel, which is where the browser lands: the page returns on #platform, so a banner written above it leaves the screen before it can be read — reported from a real screen as “the message showed for two seconds”, when nothing had moved but the page.
- A field that silently cut what you typed. The numbering prefix stops at fourteen characters so the whole number stays under the twenty some platforms accept — a kind limit, and a mute one: typing a fifteenth character made it vanish, the screen said “Settings saved”, and the only reasonable conclusion was that no rule existed. The limit is now written under the field, with its reason.
0.6.16
- The same rule, for an order keyed in by hand. Recording a company in the administration without its SIRET went through in silence, and the invoice was queued for a network that had no way to deliver it. The order screen now refuses to save before the form is posted — beside the field, with the company named — because the person who can still fix it is the one looking at the screen, not a reader of a note at the bottom of a page she has already left. The server keeps the rule too: a check in a browser is a courtesy, never a guarantee.
- The Conformité screen takes the width of the screen. The old cap left half a large monitor empty beside a table that had to wrap. The explanation stays two columns with one paragraph in each — not a single text flowing from the foot of one to the head of the other, which reads as one long passage cut in half — and each column now takes half the card rather than a fixed 476px: 818px at a window of 1920, 498px at 1280, side by side at both, and the table of periods sits 59px higher than it did. No horizontal overflow at either width.
- The order screen checks the number as well as its presence. A SIRET whose check digit is wrong was refused by the server, which meant learning about it after the page had reloaded, from a note at the bottom. The browser now runs the same arithmetic before the form is posted — La Poste exception included, because the two implementations have to agree on every number or the guard would let through what the server then refuses.
- An order keyed in by hand kept its lines untaxed, and nothing said so. WooCommerce does not work the tax out on a line added in the administration until Recalculate is pressed; the order is then saved with no VAT, and the invoice faithfully prints “0 %” — which is a claim that the supply is zero-rated, not an admission that nobody worked it out. Twenty percent that would never be declared. The document is left alone, because a document records what happened rather than what was meant, and the shop is warned at the top of the order screen while the order can still be corrected. Domestic sales only: a sale to another member state and an export are lawfully at zero, and warning about those would teach the shop to ignore the warning that matters.
Older releases are listed in changelog.txt, which ships with the plugin.
