Aller au contenu
Log in

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.

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.

  • Un compte français sur B2Brouter avec le Tax Report Setting dgfip activé. Voir les étapes 1 et 2 du guide DGFiP.
  • X-B2B-API-Version: 2026-03-02 ou 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 par https://api.b2brouter.net.

POST /accounts/{ACCOUNT_ID}/ledgers/import

Le 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).

Fenêtre de terminal
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.xml

Ré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.

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é.

#VérificationEn cas d’échec
1Content-Type: application/octet-stream406Content-Type must be application/octet-stream
2Taille du corps ≤ 100 Mo (limite IRR_TAILLE du PPF, v3.2 §3.4.2)422The payload exceeds the PPF file limit of 100 Mo
3Validation XSD par rapport au package officiel v3.2422 avec les détails de l’erreur de schéma
4Version d’API ≥ 2026-03-02422DGFiP F10 import requires API version 2026-03-02 or later
5Le compte a le paramètre dgfip activé422The account has no enabled DGFiP e-reporting configuration
6Le SIREN de <Issuer><Id> correspond à l’entreprise du compte422The <Issuer> SIREN (…) does not match the account's company
7Exactement un sous-flux (transactions ou paiements)422The 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.

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énarioRéponse
Nouvelle clé201 avec le ledger créé
Même clé, même payload200 avec le ledger déjà existant — aucun doublon n’est créé
Même clé, payload différent409Idempotency-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.

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 avec schemeId="0238", RoleCode WK), 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.

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.

ÉtatCDV PPFSignification
newImporté et validé, en attente de dépôt
sentDéposé auprès du PPF
acknowledged500 — ReçueLe PPF a reçu le fichier
depositedDépôt accepté par le PPF
registered300Terminal — déclaration enregistrée par la DGFiP
refused301Terminal — rejetée ; error_code et error_description portent le motif
errorErreur de transmission ; error_description porte le détail

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.

Fenêtre de terminal
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"
}
}
GET /ledgers/{LEDGER_ID}/download

Renvoie 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é.

GET /ledgers/{LEDGER_ID}/download_response

Renvoie le CDV reçu du PPF. Tant qu’aucun n’est arrivé, il renvoie 404.

En mode Sandbox, download et download_response renvoient 503 : il n’y a pas de vrai dépôt ni de réponses du PPF.