Soumettre un fichier d'e-reporting Flux 10
Ce guide explique comment déposer un fichier Flux 10 (e-reporting) auprès du PPF quand ton propre système le génère déjà, sans que les factures sous-jacentes passent par la facturation B2Brouter. B2Brouter valide le fichier par rapport au XSD officiel v3.2, le normalise pour le dépôt, et le transmet à la DGFiP en tant que Plateforme Agréée, en te renvoyant les états du cycle de vie CDV via webhook et API. C’est un chemin alternatif au pipeline natif, où tu envoies les données de facture en JSON et B2Brouter construit le F10 ; les deux partagent le même canal de sortie vers le PPF.
À qui s’adresse ce guide
Section intitulée « À qui s’adresse ce guide »Aux intégrateurs et éditeurs de logiciels qui produisent déjà leur propre <Report> F10 et
ont seulement besoin d’un canal accrédité pour le déposer. Si tu veux que B2Brouter génère le
F10 à partir de tes factures, n’utilise pas ce guide : consulte la section e-Reporting (Flux 10)
du guide DGFiP.
Prérequis
Section intitulée « Prérequis »- Un compte français sur B2Brouter avec le Tax Report Setting
dgfipactivé. Voir les étapes 1 et 2 du guide DGFiP. X-B2B-API-Version: 2026-03-02ou une version ultérieure.- Permissions API pour les endpoints de ledger activées sur ton plan. Si tu obtiens un
403, ouvre un ticket de support pour les faire activer. - Un fichier F10 valide par rapport au package XSD officiel v3.2.
Les exemples utilisent
https://api-staging.b2brouter.net. Pour la production, remplace parhttps://api.b2brouter.net.
Déposer le fichier
Section intitulée « Déposer le fichier »POST /accounts/{ACCOUNT_ID}/ledgers/importLe corps de la requête est le XML brut, avec Content-Type: application/octet-stream (tout
autre type de contenu est rejeté, pour que Rails n’essaie pas d’analyser le corps comme des
paramètres).
curl --request POST \ --url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/ledgers/import \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: 2026-03-02' \ --header 'Content-Type: application/octet-stream' \ --header 'Idempotency-Key: f10-2026-01-transactions-001' \ --data-binary @flux10-transactions.xmlRéponse — 201 Created :
{ "ledger": { "id": 68916, "type": "dgfip", "state": "new" }}L’id du ledger est l’identifiant que tu utiliseras pour suivre tout le cycle de vie. Conserve-le.
Structure minimale du fichier
Section intitulée « Structure minimale du fichier »Le fichier est un <Report> sans espace de noms. B2Brouter y lit trois choses pour décider s’il
peut être déposé : l’<Issuer>, le sous-flux déclaré, et la validité XSD.
<?xml version="1.0" encoding="UTF-8"?><Report xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ReportDocument> <Id>your-identifier</Id> <Name>Déclaration Transactions Janvier 2026</Name> <IssueDateTime> <DateTimeString>202602110400</DateTimeString> </IssueDateTime> <TypeCode>IN</TypeCode> <Sender> <!-- Remplacé par l'identité de PA de B2Brouter au moment du dépôt --> <Id schemeId="0238">0426</Id> <Name>PDP426</Name> <RoleCode>WK</RoleCode> <URIUniversalCommunication> <URIID>contact@exemple.fr</URIID> </URIUniversalCommunication> </Sender> <Issuer> <!-- Doit correspondre au SIREN de l'entreprise du compte de destination --> <Id schemeId="0002">832987911</Id> <Name>METACORTEX</Name> <RoleCode>SE</RoleCode> <URIUniversalCommunication> <URIID>contact@metacortex.fr</URIID> </URIUniversalCommunication> </Issuer> </ReportDocument> <TransactionsReport> <!-- … ou <PaymentsReport>, mais pas les deux en même temps --> </TransactionsReport></Report>Un sous-flux par dépôt. Le PPF transmet les transactions et les paiements séparément (spec
v3.2 §3.7.7) : un <Report> doit porter <TransactionsReport> ou <PaymentsReport>. Le
sous-flux déclaré détermine le mode du ledger. Un rapport portant les deux, ou aucun des deux,
est rejeté.
Validations, dans l’ordre
Section intitulée « Validations, dans l’ordre »| # | Vérification | En cas d’échec |
|---|---|---|
| 1 | Content-Type: application/octet-stream | 406 — Content-Type must be application/octet-stream |
| 2 | Taille du corps ≤ 100 Mo (limite IRR_TAILLE du PPF, v3.2 §3.4.2) | 422 — The payload exceeds the PPF file limit of 100 Mo |
| 3 | Validation XSD par rapport au package officiel v3.2 | 422 avec les détails de l’erreur de schéma |
| 4 | Version d’API ≥ 2026-03-02 | 422 — DGFiP F10 import requires API version 2026-03-02 or later |
| 5 | Le compte a le paramètre dgfip activé | 422 — The account has no enabled DGFiP e-reporting configuration |
| 6 | Le SIREN de <Issuer><Id> correspond à l’entreprise du compte | 422 — The <Issuer> SIREN (…) does not match the account's company |
| 7 | Exactement un sous-flux (transactions ou paiements) | 422 — The report carries both transactions and payments; split it into two deposits ou The report carries neither transactions nor payments |
L’élément racine détermine l’autorité : un <Report> sans espace de noms est interprété comme
un F10 DGFiP ; toute autre racine continue d’être traitée comme un ledger Verifactu, donc
l’import Verifactu continue de fonctionner dans toutes les versions d’API.
Idempotence
Section intitulée « Idempotence »Envoie un en-tête Idempotency-Key à chaque dépôt. Si tu n’en envoies pas, nous utilisons le
SHA256 du payload, donc soumettre à nouveau un fichier identique est aussi idempotent.
| Scénario | Réponse |
|---|---|
| Nouvelle clé | 201 avec le ledger créé |
| Même clé, même payload | 200 avec le ledger déjà existant — aucun doublon n’est créé |
| Même clé, payload différent | 409 — Idempotency-Key already used with a different payload |
La clé est unique par compte. Les clés de plus de 64 caractères ou contenant des caractères non ASCII sont stockées sous forme de condensé SHA256 ; le comportement est le même.
Normalisation du dépôt
Section intitulée « Normalisation du dépôt »Avant de transmettre, B2Brouter réécrit deux nœuds de ton fichier :
<ReportDocument><Id>devient l’id du ledger. C’est la clé que le PPF utilise pour corréler les CDV en retour ; si une valeur choisie par le client était conservée, un dépôt pourrait s’attribuer les réponses d’un ledger appartenant à un autre compte.<ReportDocument><Sender>devient l’identité de Plateforme Agréée de B2Brouter (matricule avecschemeId="0238",RoleCodeWK), puisque c’est nous qui déposons auprès du PPF. L’AIFE a confirmé par écrit que cette normalisation de dépôt est acceptable.
Le reste du fichier n’est pas modifié, et la soumission originale est conservée exactement telle que nous l’avons reçue comme pièce jointe d’audit sur le ledger.
Soumission au PPF
Section intitulée « Soumission au PPF »Le ledger importé reste à l’état new, et le cron d’envoi le récupère lors de sa première
exécution après minuit le jour du dépôt : en pratique, il est déposé auprès du PPF le
lendemain. Le transport est un dépôt SFTP vers le PPF (tar.gz avec l’enveloppe F10).
Le régime de TVA n’entre pas en jeu pour les fichiers importés : la périodisation par régime est une fonction du pipeline natif. Ici, la cadence est celle du dépôt, et la période déclarée est celle que tu écris dans le fichier.
Suivre le cycle de vie
Section intitulée « Suivre le cycle de vie »États du ledger
Section intitulée « États du ledger »| État | CDV PPF | Signification |
|---|---|---|
new | — | Importé et validé, en attente de dépôt |
sent | — | Déposé auprès du PPF |
acknowledged | 500 — Reçue | Le PPF a reçu le fichier |
deposited | — | Dépôt accepté par le PPF |
registered | 300 | ✅ Terminal — déclaration enregistrée par la DGFiP |
refused | 301 | ❌ Terminal — rejetée ; error_code et error_description portent le motif |
error | — | Erreur de transmission ; error_description porte le détail |
Webhooks (recommandé)
Section intitulée « Webhooks (recommandé) »Abonne-toi à l’événement ledger.state_change pour recevoir chaque transition sans
polling. Il se déclenche à l’entrée dans les états sent, error, acknowledged,
deposited, registered et refused.
{ "web_hook": { "url": "https://example.com/hooks", "events": ["ledger.state_change"] }}Le corps que tu reçois porte l’id du compte et le ledger complet :
{ "account_id": 42, "object": { "object": "ledger", "id": 68916, "state": "registered", "mode": null, "error_code": null, "error_description": null, "document_type_code": "xml.ledger.dgfip.transactions", "sent_at": "2026-07-25T02:04:11.000Z", "created_at": "2026-07-24T10:12:03.000Z" }}Si deux CDV arrivent rapprochés, l’état déjà remplacé n’est pas livré : tu reçois toujours l’état actuel, pas nécessairement une livraison par transition. Vérifie le ledger si tu as besoin de confirmer l’état actuel. Pour la vérification de signature des webhooks, consulte le guide des webhooks.
Vérifier l’état
Section intitulée « Vérifier l’état »curl --request GET \ --url https://api-staging.b2brouter.net/ledgers/{LEDGER_ID} \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: 2026-03-02'{ "ledger": { "id": 68916, "type": "dgfip", "state": "refused", "error_code": "303", "error_description": null, "created_at": "2026-07-24T10:12:03.000Z", "sent_at": "2026-07-25T02:04:11.000Z" }}Télécharger le fichier déposé
Section intitulée « Télécharger le fichier déposé »GET /ledgers/{LEDGER_ID}/downloadRenvoie le XML normalisé que nous avons déposé (avec <Id> et <Sender> réécrits),
disponible dès le moment de l’import. C’est le document à conserver comme preuve de ce qui a
été déclaré.
Télécharger la réponse du PPF
Section intitulée « Télécharger la réponse du PPF »GET /ledgers/{LEDGER_ID}/download_responseRenvoie le CDV reçu du PPF. Tant qu’aucun n’est arrivé, il renvoie 404.
En mode Sandbox,
downloadetdownload_responserenvoient 503 : il n’y a pas de vrai dépôt ni de réponses du PPF.