Ir al contenido
Log in

Envío de un archivo de Flux 10 e-reporting generado por ti

Esta guía explica cómo depositar en el PPF un archivo de Flux 10 (e-reporting) que ya genera tu sistema, sin que las facturas subyacentes pasen por la facturación de B2Brouter. B2Brouter valida el archivo contra el XSD oficial v3.2, lo normaliza para el depósito y lo transmite a la DGFiP como Plateforme Agréée, devolviéndote los estados del ciclo CDV por webhook y por API. Es un camino alternativo al pipeline nativo (en el que envías los datos de la factura en JSON y B2Brouter construye el F10); ambos comparten el mismo canal de salida hacia el PPF.

A integradores y editores de software que ya producen su propio <Report> F10 y solo necesitan un canal acreditado para depositarlo. Si lo que quieres es que B2Brouter genere el F10 a partir de tus facturas, no uses esta guía: consulta la sección de e-Reporting (Flux 10) de la guía DGFiP.

  • Una cuenta francesa en B2Brouter con el Tax Report Setting dgfip habilitado. Consulta los pasos 1 y 2 de la guía DGFiP.
  • X-B2B-API-Version: 2026-03-02 o posterior.
  • Los permisos de API para los endpoints de ledgers habilitados en tu plan. Si recibes un 403, abre un tique de soporte para que te los habiliten.
  • El archivo F10 válido contra el paquete XSD oficial v3.2.

Los ejemplos usan https://api-staging.b2brouter.net. Para producción, sustitúyelo por https://api.b2brouter.net.

POST /accounts/{ACCOUNT_ID}/ledgers/import

El cuerpo de la petición es el XML en crudo, con Content-Type: application/octet-stream (cualquier otro content type se rechaza, así evitamos que Rails intente interpretar el cuerpo como parámetros).

Ventana 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

Respuesta — 201 Created:

{
"ledger": {
"id": 68916,
"type": "dgfip",
"state": "new"
}
}

El id del ledger es el identificador con el que seguirás todo el ciclo de vida. Guárdalo.

El archivo es un <Report> sin namespace. B2Brouter lee de él tres cosas para decidir si puede depositarlo: el <Issuer>, el subflujo declarado y la validez XSD.

<?xml version="1.0" encoding="UTF-8"?>
<Report xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ReportDocument>
<Id>tu-identificador</Id>
<Name>Déclaration Transactions Janvier 2026</Name>
<IssueDateTime>
<DateTimeString>202602110400</DateTimeString>
</IssueDateTime>
<TypeCode>IN</TypeCode>
<Sender>
<!-- Lo sustituimos por la identidad de PA de B2Brouter al depositar -->
<Id schemeId="0238">0426</Id>
<Name>PDP426</Name>
<RoleCode>WK</RoleCode>
<URIUniversalCommunication>
<URIID>contact@exemple.fr</URIID>
</URIUniversalCommunication>
</Sender>
<Issuer>
<!-- Debe coincidir con el SIREN de la empresa de la cuenta destino -->
<Id schemeId="0002">832987911</Id>
<Name>METACORTEX</Name>
<RoleCode>SE</RoleCode>
<URIUniversalCommunication>
<URIID>contact@metacortex.fr</URIID>
</URIUniversalCommunication>
</Issuer>
</ReportDocument>
<TransactionsReport>
<!-- … o <PaymentsReport>, pero no los dos a la vez -->
</TransactionsReport>
</Report>

Un solo subflujo por depósito. El PPF transmite transacciones y cobros por separado (spec v3.2 §3.7.7): un <Report> debe llevar <TransactionsReport> o <PaymentsReport>. El subflujo declarado determina el modo del ledger. Un report con ambos, o sin ninguno de los dos, se rechaza.

#ComprobaciónSi falla
1Content-Type: application/octet-stream406Content-Type must be application/octet-stream
2Tamaño del cuerpo ≤ 100 Mo (límite IRR_TAILLE del PPF, v3.2 §3.4.2)422The payload exceeds the PPF file limit of 100 Mo
3Validación XSD contra el paquete oficial v3.2422 con el detalle de los errores del esquema
4Versión de API ≥ 2026-03-02422DGFiP F10 import requires API version 2026-03-02 or later
5La cuenta tiene el setting dgfip habilitado422The account has no enabled DGFiP e-reporting configuration
6El SIREN de <Issuer><Id> coincide con la empresa de la cuenta422The <Issuer> SIREN (…) does not match the account's company
7Un único subflujo (transactions o payments)422The report carries both transactions and payments; split it into two deposits o The report carries neither transactions nor payments

El elemento raíz decide la autoridad: un <Report> sin namespace se interpreta como F10 de la DGFiP; cualquier otra raíz se sigue tratando como un ledger Verifactu, de modo que la importación de Verifactu sigue funcionando en todas las versiones de API.

Envía una cabecera Idempotency-Key con cada depósito. Si no envías ninguna, usamos el SHA256 del payload, de modo que reenviar un archivo idéntico también es idempotente.

EscenarioRespuesta
Clave nueva201 con el ledger creado
Misma clave, mismo payload200 con el ledger que ya existía; no se crea ningún duplicado
Misma clave, payload distinto409Idempotency-Key already used with a different payload

La clave es única por cuenta. Las claves de más de 64 caracteres o con caracteres no ASCII se almacenan como resumen SHA256; el comportamiento es el mismo.

Antes de transmitir, B2Brouter reescribe dos nodos de tu archivo:

  • <ReportDocument><Id> pasa a ser el id del ledger. Es la clave con la que el PPF correlaciona los CDV de retorno; si se mantuviera un valor elegido por el cliente, un depósito podría reclamar las respuestas de un ledger de otra cuenta.
  • <ReportDocument><Sender> pasa a ser la identidad de Plateforme Agréée de B2Brouter (matricule con schemeId="0238", RoleCode WK), porque quien deposita en el PPF somos nosotros. La AIFE ha confirmado por escrito que esta normalización de depósito es aceptable.

El resto del archivo no se toca, y el envío original se conserva tal como lo hemos recibido como adjunto de auditoría del ledger.

El ledger importado queda en estado new y el cron de envío lo recoge en su primera ejecución tras la medianoche del día del depósito: en la práctica, se deposita en el PPF al día siguiente. El transporte es un depósito SFTP al PPF (tar.gz con el envelope F10).

El régimen de IVA no interviene en los archivos importados: la periodización por régimen es una función del pipeline nativo. Aquí la cadencia es la del depósito, y el periodo declarado es el que tú escribes en el archivo.

EstadoCDV del PPFSignificado
newImportado y validado, pendiente de depósito
sentDepositado en el PPF
acknowledged500 — ReçueEl PPF ha recibido el archivo
depositedDepósito aceptado por el PPF
registered300Terminal — declaración registrada por la DGFiP
refused301Terminal — rechazada; error_code y error_description traen el motivo
errorError de transmisión; error_description trae el detalle

Suscríbete al evento ledger.state_change para recibir cada transición sin necesidad de hacer polling. Se dispara al entrar en sent, error, acknowledged, deposited, registered y refused.

{
"web_hook": {
"url": "https://example.com/hooks",
"events": ["ledger.state_change"]
}
}

El cuerpo que recibes trae el id de la cuenta y el ledger completo:

{
"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 llegan dos CDV muy seguidos, el estado ya superado no se entrega: siempre recibes el estado vigente, no necesariamente una entrega por cada transición. Consulta el ledger si necesitas confirmar el estado actual. Para la verificación de la firma del webhook, consulta la guía de webhooks.

Ventana 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

Devuelve el XML normalizado que hemos depositado (con el <Id> y el <Sender> reescritos), disponible desde el momento de la importación. Es el documento que hay que conservar como prueba de lo declarado.

GET /ledgers/{LEDGER_ID}/download_response

Devuelve el CDV recibido del PPF. Mientras no haya ninguno, devuelve 404.

En modo Sandbox, download y download_response devuelven 503: no hay depósito real ni respuestas del PPF.