We applied the official French rulebook to our own output this week, and it found more than France. Three of the changes below affect every country, not just French invoices.
French invoices carry the three legal mentions
BR-FR-05 of the FNFE-MPE socle requires three mentions in the invoice notes —
the flat recovery indemnity, the late-payment penalties, and the early-payment
discount or the statement that there is none. Measured against the official
schematrons, none of our documents carried them, and neither did the
reference template of a registered French platform we compared against.
They are now written for you whenever an invoice declares the French régime.
Each one gets its normative marker (#PMT#, #PMD#, #AAB#) from us, and a
statutory default sentence you can replace:
await peppol.invoices.send({
// …
france: {
cadreDeFacturation: "S1",
legalMentions: {
latePaymentPenalties: "Pénalités de retard : 12 % par an.",
earlyPaymentDiscount: "Escompte de 2 % pour paiement sous 10 jours.",
},
},
});
Two of the three come from your terms of sale, so only you can write them. The
€40 indemnity is fixed by article D441-5 and is the same for every French
issuer, so its default is usually the right one. Precedence runs mention by
mention, never as a block: the invoice field wins, then the mention saved on
your legal entity, then the statutory wording. An entry you omit — or send empty
or blank — counts as absent and falls through to the next level, so if that
mention is saved on your legal entity it is the one that ships, not the
statutory text. Overriding one sentence leaves the other two alone. Each entry
must be a string; a null is refused with 400, so omit the field instead.
Sending your own invoices? Save the three once on your legal entity from the getpeppr console instead, and omit the block. Sending on behalf of your customers? Their terms of sale live in your system, so send them here per invoice — we do not store a platform's customers' terms.
⚠️ You never write the marker yourself. Rule BR-FR-06 allows one occurrence of
each, so a marker inside your own text — or inside the invoice's plain note —
is refused with 400 invoices.france_legal_mentions_invalid before anything is
submitted.
companyIdScheme reaches the XML — every country
Party.companyIdScheme has been in the public type for a long time, documented
as the scheme of the registration number and read by our country rules to make
decisions. The UBL builder never wrote it: every document carried a bare
<cbc:CompanyID> with no schemeID.
It is now emitted. If you supply companyId without a scheme, nothing changes —
a bare company ID is still legal. If you supply both, the attribute appears
where the rulebooks look for it, which is what French rule BR-FR-10 requires
of a seller's SIREN and what several national rulebooks expect elsewhere.
An attachment given only as a url is now refused
The Attachment.url field was documented as an alternative to embedded content.
It was not one: a Peppol document carries the file itself, our provider's
contract has no field for a link, and the whole attachment was dropped before
dispatch. The call returned 201 for an invoice with no supporting document at
all.
POST /v1/invoices now answers 422 invoices.attachment_url_not_supported for
any non-empty url.
⚠️ This can refuse a call that used to succeed. If you send url alongside
content and mimeType, the invoice went out with the file embedded and the
link quietly discarded — and our local builder could pick the link where the
gateway picked the file, so the preview and the sent document disagreed. Send
content, mimeType and filename, and drop url.
url still works in the local UBL builder (peppol.toXml(...)), which can
write it; the refusal is on the send path, where the document is produced by our
provider.
A French sender needs a SIREN, and we say so before sending
An invoice declaring the French régime is now refused with
422 invoices.france_regime_not_eligible when the issuing identity carries no
SIREN under scheme 0002 — nine digits exactly, which is what BR-FR-10 puts
on the document. Register it on that legal entity, or omit the france block to
send an ordinary Peppol invoice.
A SIRET (fourteen digits) under the same scheme does not satisfy the rule, and is refused too.
⚠️ Registering it is necessary, and it is not on its own sufficient — and we
would rather tell you than let you find out. Measured on a transmitted
document on 22 September 2026: when the same legal entity also carries a
directory identifier, the network operator writes THAT one into the outgoing
document, and BR-FR-10 fails on it anyway. We require the SIREN because the
rule requires it; we do not yet control which identifier is written. That part
is open on our side, not yours.
Update, 22 September 2026. We found what decides it: the network operator
writes the first non-tax identifier registered on your legal entity. Register
the SIREN (scheme 0002) before the directory identifier (0225) and the rule
holds — measured on transmitted documents. A declared French invoice is now
refused before submission, with 422 france_regime_not_eligible, when the SIREN
is not first; the France guide explains the fix.
Also
Invoice.note is deprecated at our provider's contract; we now send the notes
array instead. No change to how you supply a note.
New exports for anyone building or checking documents locally:
buildFranceLegalMentions, validateFranceNotes,
FRANCE_LEGAL_MENTION_DEFAULTS, and the FranceLegalMentions /
FranceNoteProblem types.
⛔ None of this makes a document accepted by the French tax circuit. It makes it satisfy the rules we can check before sending — which, until this week, we could not check at all.