Sending and receiving Peppol documents in France for your own company

Getting started with Peppol e-invoicing for your own French company: register and verify the company, send French UBL, CII or Factur-X invoices, pick up incoming documents, report invoice lifecycle statuses, go live. French UBL, CII and Factur-X on a French-accredited access point, with a signed mandate and its own regulated process.

This guide walks through everything needed to exchange Peppol documents for a company registered in France, assuming you are setting up your own French company, and that the company sends and receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation.

What you are setting up

You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers.

The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the Recommand dashboard, and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing integrations can also connect Recommand to accounting or invoicing software you already use, with no code at all.

A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan.

Onboarding companies that are not yours?

If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to Many companies. The API is the same; what changes is how companies, verification and billing are organised.

Peppol in France

French domestic e-invoicing follows the French e-invoicing reform rather than plain Peppol BIS 3. Recommand covers the French specifics for you, but they do change what you send and how a company is onboarded.

What is specific to France:

  • A French-accredited access point and SMP. Companies you register with country FR are automatically published on a French-accredited SMP and exchange documents through the matching access point. You do not choose or configure this: it follows from the company's country.
  • A signed mandate. Before a French company can operate, its authorised representative signs a mandate that lets that accredited platform act for the company, and the file is reviewed before the company goes live. This is the one step in this guide that is not instant, so start it early.
  • French document formats. Invoices and credit notes travel as French CIUS or Extended UBL, CII D22B (CIUS or Extended), or Factur-X (a PDF/A-3 with the CII XML embedded), next to plain Peppol BIS 3 UBL.
  • Two processes. The same document types are published for a regulated process (urn:peppol:france:billing:regulated, transactions inside the French e-invoicing perimeter) and a non-regulated one (urn:peppol:france:billing:non-regulated, transactions outside it).
  • Mandatory content. French invoices carry a billing mode and three statements (recovery costs, late-payment penalties, early-payment discount) that plain EN 16931 does not require. They go in a countrySpecific block.
  • Lifecycle statuses and e-reporting. Inside the perimeter, receivers report back on the invoices they receive, and B2C or international B2B transactions have to be reported.
  • Identifiers are SIREN-based. French companies are published under scheme 0225.

Dates and legal scope

The reform phases the obligations in over time: from 1 September 2026 every company must be able to receive electronic invoices, with issuance starting for large and mid-size companies, and from 1 September 2027 issuance applies to small and micro companies as well. Confirm the schedule and what falls inside the perimeter with your accountant or legal advisor — this documentation describes what the API does, not what your obligations are.

Create your account and API credentials

  1. Sign up at app.recommand.eu/signup.
  2. Your account starts with a team. The team holds your company, your subscription and your document history, and you can invite colleagues to it.
  3. Create an API key on the API keys page. Note the key, the secret and your team ID.
  4. Check the credentials with a request that needs no data of its own:
curl -X GET https://app.recommand.eu/api/v1/companies \
  -u key_xxx:secret_xxx

All endpoints in this guide live under https://app.recommand.eu/api/v1 and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the authentication guide.

Not planning to write any code?

Sending and receiving can also be driven entirely from the dashboard or through an integration, and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the account page.

Try it safely first

You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a playground team first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed.

Open the team switcher at the top of the dashboard and pick Add playground. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away — there is nothing to set up beyond that.

Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team.

Two things worth knowing before you start:

  • POST /:companyId/generate takes the same body as the send endpoint and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. It also returns the resolved documentType, doctypeId and processId.
  • Failure addresses. In a playground that is not connected to the Peppol Test Network, sending to 404:404 or 0208:1234567894 always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error.

A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See how can I test without sending real invoices.

Playgrounds are separate

Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company.

Register the company

You are registering one company, once, so the dashboard is the shortest path.

  1. Open Companies and start the company wizard.
  2. Fill in the legal name, address and country, plus the identifiers described in the next section.
  3. Choose whether the company should also receive documents over Peppol, or only send them.
  4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you.

Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page — every API call for sending and receiving takes it in the path.

Rather create it from code?

The create company endpoint does exactly the same thing, and returns the company id and a verificationUrl in one response. It is worth using when company creation is part of a flow you are automating — which is likely the case if you are registering many companies. Switch the first answer above to Many companies for that version.

More than one entity?

Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume.

French identifiers and Peppol address

In France the identifier you register decides whether your documents will pass validation later, so it is worth getting exactly right.

FieldFrench value
country"FR"
enterpriseNumberThe nine-digit SIREN of the company
enterpriseNumberScheme"0002"
vatNumberFR + the French VAT number
company.json
{
  "name": "Société de Test SAS",
  "address": "10 rue de la Paix",
  "postalCode": "75002",
  "city": "Paris",
  "country": "FR",
  "enterpriseNumber": "133512194",
  "enterpriseNumberScheme": "0002",
  "vatNumber": "FR23133512194"
}

Use the SIREN with scheme 0002

French regulated invoices must carry the seller's nine-digit SIREN as enterpriseNumber with enterpriseNumberScheme "0002". Because the seller block of a document defaults to the company's own details, a company registered with a SIRET or without the scheme produces invoices that are rejected at validation time. Register the SIREN, and name a specific establishment through the document's delivery.locationIdentifier (scheme 0009) when you need to.

One Peppol identifier is registered for the company:

  • 0225:133512194 — the French electronic address

The company's Peppol address is therefore 0225: followed by the SIREN. French addresses may also carry a routing suffix, as in 0225:987654321_STATUTS; treat the whole string after the scheme as the identifier when a recipient gives you one.

Both SIREN (9 digits) and SIRET (14 digits) are checked with the Luhn algorithm before they are filed, and numbers that disagree with each other are refused rather than guessed at.

Registering for both directions

Sending needs no registration of its own; receiving does. So register the company as a recipient, which is the default:

{
  "isSmpRecipient": true
}

What that means:

  • The company becomes findable on the Peppol network and can be delivered to through Recommand's access point, while sending its own documents out through the same access point.
  • Recipient registration is exclusive. If the company already receives through another Peppol provider, registration fails until it is deregistered there. What that takes depends on the country, which the next section covers.
  • The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down.
  • The company is only published once it is verified.

Sending first, receiving later

If the company still receives elsewhere and you do not want to move that yet, register it with isSmpRecipient: false and start with sending only. Flipping the field later publishes it as a recipient.

Where a French company is published

A French company is published on the French-accredited SMP, and it exchanges documents through the matching access point. This follows from the company's country: there is nothing to choose or configure.

Two consequences for the order of your onboarding:

  • The mandate gates the go-live. The accredited platform only acts for the company once the signed mandate has been accepted, so the company is not operational the minute it is created. The verification section below covers that step; start it early.
  • Deregister elsewhere first. Recipient registration is exclusive here as well, and France has no automatic migration path — a company that currently receives through another platform has to be deregistered there before it can be registered with Recommand.

Sign the mandate and verify the company

French companies go through the same identity check as everyone else, plus two steps that are specific to France: the representative signs a mandate, and the resulting file is reviewed before the company goes live.

  1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the verify company endpoint).
  2. Read and sign the mandate. The verification page shows the mandate that authorises the French-accredited platform to act for the company on the Peppol network, naming the company by its SIREN and the establishment it is filed under. The representative accepts it before the identity check starts.
  3. Complete the identity check. The identity verification is what signs the mandate: the proof reference is recorded on it.
  4. Wait for the review. The signed mandate and the company's details are filed with the accredited platform, and the verification sits in review until that file is accepted. Only then does isVerified become true and the company start operating.

In some cases manual verification by our team will be required. If that's the case, isVerified will remain false until this manual verification is completed. The user is informed of this in the verification process.

Plan the review in

This is the one step of French onboarding that is not immediate. Start verification as soon as the company is created, and do not promise your users a same-minute go-live for France. If a file seems stuck, mail support@recommand.eu with the company ID.

Playgrounds skip the mandate

Companies in a playground team are never filed with the accredited platform, so there is no mandate and no review. Test the French flow in a playground first, then run the real thing once.

Verifying once, in the dashboard

You have one company, and it is verified once. There is nothing here worth automating: open Companies in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is.

The page is self-contained and works in any browser — the person completing it does not need a Recommand account.

That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate.

Changing identifiers resets verification

Updating the company's vatNumber or enterpriseNumber sets isVerified back to false, and the company has to be verified again before it can exchange documents.

Pick the French document format and process

A French invoice needs three decisions: the format, the process, and the mandatory French content.

The format

Name the format with doctypeId on the send request. Without it you send plain Peppol BIS 3 UBL, which is valid on the network but not what the French reform asks for inside its perimeter.

FormatdoctypeId
France UBL CIUS invoiceurn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1
France UBL CIUS credit noteurn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1
France UBL Extended invoiceurn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::2.1
France CII CIUSurn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::D22B
France CII Extendedurn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::D22B
France Factur-Xurn:peppol:doctype:pdf+xml##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:Factur-X:1.0::D22B

The CII and Factur-X document types carry both invoices and credit notes; the documentType field of your request decides which one it is.

Start with France UBL CIUS unless you have a reason not to. Extended is for data the CIUS does not carry, and Factur-X is for recipients who want a human-readable PDF as the carrier.

The process

Set countrySpecific.businessProcess to say which side of the French perimeter the transaction is on. The document is then sent over the matching process:

businessProcessProcess identifierUse for
REGULATED (default)urn:peppol:france:billing:regulatedTransactions inside the French perimeter
NON_REGULATEDurn:peppol:france:billing:non-regulatedTransactions outside it

The recipient must have registered the document type for that process. Pass the processId to the verify document support endpoint to check exactly that combination rather than "any process".

The mandatory French content

French UBL, CII and Factur-X require a countrySpecific block with the billing mode and the three statements French invoices must carry. It is required for those document types and must be omitted for plain EN 16931 documents.

{
  "countrySpecific": {
    "country": "FR",
    "billingMode": "S1",
    "businessProcess": "REGULATED",
    "recoveryCostsNote": "Indemnité forfaitaire de 40 EUR pour frais de recouvrement.",
    "latePaymentPenaltiesNote": "Pénalités de retard exigibles au taux prévu dans les conditions générales de vente.",
    "earlyPaymentDiscountNote": "Aucun escompte accordé pour paiement anticipé."
  }
}

billingMode follows AFNOR XP Z12-012. The common ones are B1 (goods), S1 (services) and M1 (mixed); the full list, including already-paid, advance payment, subcontracting and multi-seller variants, is documented on the send document endpoint.

Invoicing outside France

The French formats and processes are for the French perimeter. A counterparty in another country is registered for the standard Peppol billing process, so a regulated document does not match anything they published.

For those invoices, send plain Peppol BIS 3 UBL and leave the countrySpecific block out with it, it belongs to the French document types only. The rest of the invoice is unchanged.

Three rules that reject a French invoice

  • The seller's enterpriseNumber must be the nine-digit SIREN with enterpriseNumberScheme "0002".
  • The currency must be EUR.
  • Factur-X needs a compliant PDF/A-3 to embed the XML in: either attach one as an embedded attachment, or let Recommand generate it with pdfGeneration.enabled.

Send a document

One endpoint sends everything: POST /:companyId/send. The companyId is the sender, recipient is the Peppol address of the receiver, and document is the invoice or credit note as JSON. Recommand will validate the document and generate the XML.

Already producing UBL or CII XML?

Raw XML sending is supported as well: set documentType to xml and pass the document string in document, along with the correct doctypeId. See working with raw UBL.

curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \
  -u key_xxx:secret_xxx \
  -H "Content-Type: application/json" \
  -d @send-invoice.json
send-invoice.json
{
  "recipient": "0208:0123456789",
  "documentType": "invoice",
  "document": {
    "invoiceNumber": "INV-2026-001",
    "issueDate": "2026-08-17",
    "dueDate": "2026-09-16",
    "currency": "EUR",
    "buyer": {
      "name": "Customer Company",
      "street": "Customer Street 1",
      "city": "Antwerp",
      "postalZone": "2000",
      "country": "BE",
      "vatNumber": "BE0987654321"
    },
    "paymentMeans": [{ "iban": "BE68539007547034" }],
    "lines": [
      {
        "name": "Consulting Services",
        "quantity": "10.00",
        "unitCode": "HUR",
        "netPriceAmount": "100.00",
        "vat": { "category": "S", "percentage": "21.00" }
      }
    ]
  }
}

The seller block is filled in from your company when you leave it out, which is usually what you want: it keeps your registered identifiers and the document in agreement. The full field reference lives in sending invoices and sending credit notes.

Worth wiring up while you are here:

  • Validation errors. Outgoing documents are always validated. A success: false response with errors keyed by field path is a document the recipient would have rejected — surface it wherever the data was typed.
  • Email fallback. Pass email.to with when: "on_peppol_failure" to fall back to email when a recipient turns out not to be reachable over Peppol, or send with recipient: null for email-only delivery. See email delivery and notifications.
  • PDFs. pdfGeneration.enabled attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via attachments; see adding attachments.

For a full field reference, see sending invoices and sending credit notes.

Sending without writing code

The same send is available two other ways, and they mix freely with the API:

  • From the dashboard. Send document takes the recipient and the invoice lines, previews what the recipient will get, and remembers your usual settings. You can also drop an existing UBL or CII XML file into the upload zone if your software already produces one.
  • From your accounting or invoicing software. If you use one of the supported tools, let it do the work: your invoices flow to Recommand and out over Peppol without retyping. See integrations for the current list, including Microsoft Business Central, Exact Online, Yuki, ClearFacts, ERPNext and Harvest.

Every outgoing document is validated

Whichever route you use, Recommand validates a document before it leaves. If a field is missing or malformed you get a clear error instead of a rejection from the recipient days later. See the troubleshooting guide for the errors you are most likely to run into.

Document types registered for you

A French company is published for the whole French set, all on the regulated process, so any sender inside the perimeter can reach it in the format they prefer:

Document typeRegistered process
Invoice + credit note (Peppol BIS 3 UBL)urn:peppol:france:billing:regulated
Invoice + credit note (France UBL CIUS)urn:peppol:france:billing:regulated
Invoice + credit note (France UBL Extended)urn:peppol:france:billing:regulated
Invoice + credit note (France CII CIUS)urn:peppol:france:billing:regulated
Invoice + credit note (France CII Extended)urn:peppol:france:billing:regulated
Factur-X invoice + credit noteurn:peppol:france:billing:regulated
Invoice lifecycle status (CDAR)urn:peppol:france:billing:regulated

Whichever format arrives, you read the same parsed document out of the API. For Factur-X, the CII XML is extracted from the PDF/A-3 and parsed like any other document, and the original PDF is kept and included in the document's download package.

Trading outside the perimeter

The defaults cover the regulated process. If counterparties will send you documents over urn:peppol:france:billing:non-regulated, register the same document types for that process as well with the create company document type endpoint.

Pick up incoming documents

Once the company is published as a recipient, everything sent to it arrives in Recommand automatically. There are two ways to get the documents into your own systems.

Register an endpoint once with the create webhook endpoint and events are pushed to you as they happen, document.received among them:

curl -X POST https://app.recommand.eu/api/v1/webhooks \
  -u key_xxx:secret_xxx \
  -H "Content-Type: application/json" \
  -d @create-webhook.json
create-webhook.json
{
  "url": "https://your-app.example/webhooks/recommand",
  "companyId": null,
  "secret": "your_webhook_signing_secret"
}

Pass a secret and verify the HMAC SHA-256 signature on every delivery before you trust the payload, then acknowledge with a 200 before doing the heavy processing. Both are covered in working with webhooks.

Polling the inbox

If you would rather pull, the inbox endpoint lists unread documents, and mark as read drops one off the list once your system has it. Fetch details, the original XML or a rendered PDF from the documents endpoints.

Receiving without writing code

  • In the dashboard. Incoming invoices appear under Sent and received, with the original XML, a readable rendering, attachments and the delivery history.
  • By email. Add notification email addresses per company so incoming documents land in the mailbox your bookkeeping already watches, attachments included. See email delivery and notifications.
  • In your accounting software. Forward incoming documents straight to Exact Online, Yuki, ClearFacts or another supported tool, see integrations.

Two things worth setting up early, whichever route you take:

  • Labels and suppliers to keep documents organised as volume grows, see suppliers and labels.
  • Rules to act on incoming documents automatically: forwarding, labelling, notifying, see rules.

The full picture, including retries and idempotency, is in receiving documents.

Report back on the invoices you receive

Inside the French perimeter, receiving an invoice comes with an obligation the other two countries do not have: you report its lifecycle back to the sender. Recommand models those status messages as a document type of their own, frenchInvoicingCdar, so you send them the same way you send anything else.

Received and made available are sent for you

When an invoice arrives, Recommand automatically sends the transmission statuses back to the sender: 202 (received) when the document reaches the access point, and 203 (made available) when it is delivered to you. You only send the later processing statuses.

await fetch(`https://app.recommand.eu/api/v1/${companyId}/send`, {
  method: "POST",
  headers: { Authorization: auth, "Content-Type": "application/json" },
  body: JSON.stringify({
    recipient: "0225:987654321",
    documentType: "frenchInvoicingCdar",
    document: {
      businessProcess: "REGULATED",
      senderRole: "WK",
      issuerRole: "BY",
      issuerLegalId: "123456789",
      issuerLegalIdScheme: "0002",
      recipientRole: "SE",
      statusCode: "205",
      statusDate: "2026-08-17T14:05:09",
      invoiceId: "INV-2026-001",
      invoiceTypeCode: "380",
      invoiceIssueDate: "2026-08-17",
      sellerLegalId: "987654321",
      sellerLegalIdScheme: "0002",
    },
  }),
});

The processing statuses that matter most on the receiving side:

StatusMeaning
204Taken in charge (processing started)
205Approved
206Partially approved
207In dispute
210Refused
211Payment sent

A refusal, partial approval or dispute carries a coded reason (DOUBLON, TX_TVA_ERR, NON_CONFORME, …) and an optional free-text note, so the sender knows what to fix. The full status and reason lists are on the send document endpoint.

Incoming CDAR messages are parsed, stored and shown next to your other documents, and delivered through your existing webhooks and notifications — so this is also how you learn what your customers did with the invoices you sent them, including the 202 and 203 their access point sent when they received yours.

Going live

A short list before you start sending or receiving real invoices:

  • A valid subscription, so sending is not blocked. Playgrounds skip that check; production does not.
  • The company verified, with isVerified true. Until then it cannot exchange documents.
  • Errors surfaced, not swallowed. Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it.
  • Webhook endpoint hardened, if you took that route: signature verification, a fast 200, retries and idempotency on your side.
  • One real document sent and received, ideally between two companies you control, so you have seen both ends.
  • Notification addresses set, so incoming documents also reach a mailbox somebody reads.

Tell your customers and suppliers

Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land.

Before you go live in France

France adds a few checks to the list above, all of them things that only show up once real documents move:

  • The mandate is accepted. isVerified is true, which for a French company means the signed mandate cleared its review. Plan this in: it is the one step that is not instant.
  • The company carries the SIREN under scheme 0002. Both the documents you send and the mandate itself are built from the company's own identifiers, so a SIRET or a missing scheme surfaces as rejected documents rather than as a registration error.
  • You know which side of the perimeter you are on. Regulated is the default; transactions outside it have to say so explicitly, and the counterparty has to be registered for the process you use.

If the company sends documents, two more:

  • The format and process are what you meant. Check one document before the first real send: the preview in the dashboard, or generate from the API, shows the resolved doctypeId and processId.
  • Invoices are in EUR, with the billing mode and the three mandatory statements filled in.

Selling to consumers as well?

B2B invoices are only half of the French obligation. If the company also sells to private individuals, its daily B2C totals (and international B2B totals) have to be reported separately, through the French B2C reporting endpoint.

Where to get help

  • Troubleshooting. Common rejections, delivery failures and validation errors are collected in the troubleshooting guide.
  • Questions. The FAQ covers Peppol, addressing, VAT and billing.
  • Email. support@recommand.eu:include the company ID and, for a delivery problem, the document ID.
  • Discord. Join the server for release announcements and quick questions.
  • Keep track of changes. New endpoints and behaviour are recorded in the changelog.