Skip to content
Log in

[Beta] Guide SII

[Beta] Déclarer les enregistrements de TVA à l’AEAT via le SII (Suministro Inmediato de Información) avec l’API B2Brouter

Section titled “[Beta] Déclarer les enregistrements de TVA à l’AEAT via le SII (Suministro Inmediato de Información) avec l’API B2Brouter”

[Beta] — staging uniquement. L’API JSON Tax Report pour le SII décrite dans ce guide est actuellement disponible sur l’environnement de staging (https://api-staging.b2brouter.net) pour les tests d’intégration. Elle n’est pas encore activée en production. Les noms de champs, les endpoints et le comportement peuvent encore changer avant la mise en production.

Le système espagnol Suministro Inmediato de Información (SII) oblige les entreprises enregistrées à tenir leurs livres de TVA — factures émises, factures reçues, biens d’investissement, opérations intra-UE, transactions en espèces supérieures à 6 000 €, et autres — soumis en temps quasi réel à l’AEAT (« Agencia Estatal de Administración Tributaria »). Le SII est obligatoire pour les Grandes Empresas (chiffre d’affaires > 6 010 121,04 €), les membres de groupes de TVA, les participants au REDEME et d’autres entreprises ayant choisi de s’y inscrire volontairement.

B2Brouter propose une API JSON Tax Report pour le SII afin que ton système n’ait pas à gérer SOAP, les certificats AEAT, les soumissions par lots, l’analyse des réponses ni les enveloppes XML par livre. Tu effectues des appels REST ; B2Brouter s’occupe du reste, en regroupant les enregistrements dans des « Libros de Registro » de l’AEAT et en les soumettant sous un certificat de Collaborateur Social.

Le SII est un système de déclaration fiscale distinct de la facturation — la facture sous-jacente ne porte aucun code QR et il n’y a aucune étape de vérification côté consommateur. Chaque enregistrement représente une entrée dans un livre (une facture émise, une facture reçue, la prorata annuelle d’un bien d’investissement, etc.). L’AEAT collecte les enregistrements tout au long de l’année et les utilise pour le rapprochement croisé de la TVA.

Le SII comporte neuf types de livres (« libros »), chacun avec sa propre enveloppe XML AEAT et ses règles de validation :

Type de livreCe qu’il enregistreA0 (alta)A1 (modificación)B (baja / annulation)
ExpedidaFactures émises
RecibidaFactures reçues
InversionBiens d’investissement (bienes de inversión)
IntracomunitariaOpérations intra-UE
MetalicoTransactions en espèces ≥ 6 000 € / contrepartie / période
SeguroOpérations d’assurance
ViajesagenciaRégime spécial des agences de voyage
CobroPaiements reçus sur factures émises
PagoPaiements effectués sur factures reçues

Cobro et Pago retournent HTTP 422 sur PATCH et DELETE — le XSD de l’AEAT ne prévoit pas de variantes A1 ni B pour ces livres.

Expedida et Recibida concentrent 98 %+ du volume en production. Les sept livres restants couvrent la longue traîne des exigences de déclaration de TVA.

Configuration et utilisation de l’API B2Brouter

Section titled “Configuration et utilisation de l’API B2Brouter”

La première étape consiste à activer l’autorité fiscale SII pour l’entreprise qui déclarera. Tu peux consulter le Tax Report Settings Guide pour une description complète. L’appel minimal :

Exemple de requête :

Terminal window
curl --request POST \
--url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/tax_report_settings' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'Content-Type: application/json' \
--data '{
"tax_report_setting": {
"code": "sii",
"start_date": "2026-04-15",
"auto_send": true
}
}'

Une fois qu’une configuration avec code: "sii" existe sur le compte, tous les appels à l’API Tax Report SII de ce compte l’utilisent.

L’API Tax Report est une famille d’endpoints qui gère les neuf livres SII. Le livre est sélectionné par le champ book_type du corps de la requête. Le champ type est SiiDocument pour tous les enregistrements SII quel que soit le livre.

POST /accounts/{ACCOUNT_ID}/tax_reports crée un enregistrement SII. Le même endpoint est utilisé par Verifactu, TicketBai et KSeF ; le champ type détermine quel ensemble de validation + quelle enveloppe XML AEAT s’applique.

La structure du payload JSON est basée sur le PEPPOL Continuous Transaction Control (CTC) — les noms de champs CTC ne correspondent pas aux noms de nœuds XML de l’AEAT. La section Équivalence entre les champs internes de tax report B2Brouter et les nœuds XML du SII ci-dessous liste le mapping pour chaque livre.

Les tax reports ont des ventilations fiscales (« desglose » en espagnol), et non des lignes de facture. Ton système agrège les lignes de facture sous-jacentes par type/catégorie fiscale et soumet les totaux de la ventilation. B2Brouter effectue la validation mais ne calcule pas les ventilations à partir des données de lignes.

Après un POST /tax_reports réussi, la réponse porte un state: "processing" et un ledger_id. Les enregistrements SII sont regroupés en « Libros de Registro » (Ledgers) côté serveur et soumis à l’AEAT de manière asynchrone. Pour suivre le cycle de vie :

  • Recommandé : configure le webhook de tax report. B2Brouter appelle ton endpoint lorsque l’enregistrement atteint un état final (registered, error, registered_with_errors, annulled ou refused).
  • Polling : appelle GET /tax_reports/{id} répétitivement jusqu’à ce que state atteigne l’une des valeurs finales.

La réponse de l’AEAT est reflétée dans trois champs spécifiques au SII sur l’enregistrement une fois reçue :

  • csv — le Código Seguro de Verificación assigné par l’AEAT
  • fecha_presentacion — le timestamp de présentation assigné par l’AEAT
  • estado — l’état interne du SII. Il commence à Nuevo, passe à Enviando pendant le transit et se stabilise sur une valeur terminale : Correcto, Incorrecto, AceptadoConErrores ou Error.

Pour les états d’erreur, le tableau errors de l’enregistrement est renseigné avec le rejet de l’AEAT, chaque entrée portant un code et une description :

{
"errors": [
{
"code": "4102",
"description": "El NIF no está identificado en el censo de la AEAT"
}
]
}

GET /tax_reports/{id}/download retourne le XML par enregistrement que B2Brouter inclura (ou a inclus) dans la soumission à l’AEAT. Le XML est généré au moment de la création et persisté, il est donc disponible immédiatement après le POST. Le paquet qui transite réellement est le XML du Ledger concaténé — voir l’API Ledgers.

PATCH /tax_reports/{id} avec les champs corrigés crée un enregistrement frère avec operacion: A1 (modificación). L’enregistrement original est conservé ; le nouveau frère est lié via corrected_by_id sur l’original et c’est lui qui est re-soumis à l’AEAT.

Le livre auquel appartient un enregistrement est fixé à la création — book_type ne peut pas être modifié sur un frère A1. Cobro et Pago retournent 422 ; leur XSD AEAT ne définit pas d’enveloppe A1.

DELETE /tax_reports/{id} crée un enregistrement frère avec operacion: B (baja / annulation). L’original est lié via annulled_by_id. Cobro et Pago retournent 422 — leur XSD AEAT ne définit pas d’enveloppe de baja.

GET /accounts/{ACCOUNT_ID}/tax_reports retourne les tax reports du compte — SII, Verifactu, TicketBai, KSeF, tous dans une seule liste. Filtre par plage de dates ou d’autres critères comme documenté dans l’endpoint de liste des tax reports.


Le livre SII le plus courant. L’entreprise déclarante est l’émettrice de la facture ; le client est la contrepartie.

Terminal window
curl --request POST \
--url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/tax_reports' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'Content-Type: application/json' \
--data '{
"tax_report": {
"type": "SiiDocument",
"book_type": "Expedida",
"invoice_number": "INV-2026-001",
"invoice_date": "2026-04-15",
"fiscal_year": 2026,
"fiscal_period": 4,
"invoice_type_code": "F1",
"special_regime_key": "01",
"description": "Servicios de consultoría",
"customer_party_name": "Cliente Ejemplo S.L.",
"customer_party_tax_id": "B87654321",
"customer_party_country": "es",
"tax_inclusive_amount": 1210.0,
"tax_amount": 210.0,
"currency": "EUR",
"tax_breakdowns": [
{
"name": "IVA",
"category": "S",
"percent": 21.0,
"taxable_base": 1000.0,
"tax_amount": 210.0
}
]
}
}'

Champs spécifiques à Expedida (en plus des champs CTC communs) :

ChampCorrespond à l’élément AEATNotes
simplified_art7273FacturaSimplificadaArticulos7.2_7.3Booléen. Émet S quand true.
reg_previo_ggeeRegPrevioGGEEoREDEMEoCompetenciaBooléen.
macrodataMacrodatoBooléen (SII), contrairement à la version string de Verifactu.
facturacion_disp_adicional_mercado_gasFacturacionDispAdicionalTerceraYsextayDelMercadoOrganizadoDelGasBooléen. Exclusif à Expedida.
sin_identif_destinatario_art_6_1_dFacturaSinIdentifDestinatarioAritculo6.1.dBooléen. Exclusif à Expedida.
succession_party_name + _tax_idEntidadSucedida > NombreRazon / NIFLes deux obligatoires ensemble quand utilisés.
billing_agreement_numberNumRegistroAcuerdoFacturacion15 caractères maximum.
external_referenceRefExterna60 caractères maximum.
tax_point_dateFechaOperacionOptionnel ; omis par défaut.

L’enveloppe XML AEAT est SuministroLRFacturasEmitidas. Les cinq flags S/N ci-dessus sont optionnels et ne sont émis que lorsqu’ils sont true.


Recibida présente l’inversion émetteur/récepteur par rapport à Expedida : le fournisseur externe est l’émetteur (enregistré dans IDEmisorFactura), et l’entreprise déclarante est la réceptrice (Titular). Utilise supplier_party_* pour le fournisseur externe ; customer_party_* n’est pas requis (les valeurs par défaut de l’entreprise sont utilisées comme récepteur).

Terminal window
curl --request POST \
--url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/tax_reports' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'Content-Type: application/json' \
--data '{
"tax_report": {
"type": "SiiDocument",
"book_type": "Recibida",
"invoice_number": "PROV-555",
"invoice_date": "2026-04-15",
"tax_point_date": "2026-04-10",
"fecha_contable": "2026-04-22",
"fiscal_year": 2026,
"fiscal_period": 4,
"invoice_type_code": "F1",
"special_regime_key": "01",
"description": "Compra de material",
"supplier_party_name": "Proveedor Test S.L.",
"supplier_party_tax_id": "A12345674",
"supplier_party_country": "es",
"tax_inclusive_amount": 1210.0,
"tax_amount": 210.0,
"cuota_deducible_in_cents": 21000,
"currency": "EUR",
"tax_breakdowns": [
{
"name": "IVA",
"category": "S",
"percent": 21.0,
"taxable_base": 1000.0,
"tax_amount": 210.0
}
]
}
}'

Champs spécifiques à Recibida :

ChampCorrespond à l’élément AEATNotes
supplier_party_tax_id / _nameIDEmisorFactura > NIF / Contraparte > NombreRazonLe fournisseur externe — l’émetteur de la facture reçue.
supplier_party_countryIDOtro > CodigoPaisQuand ce n’est pas es, l’émetteur est rendu via IDOtro au lieu de NIF.
tax_point_dateFechaOperacionDate de l’opération/service. Omis quand non fourni.
fecha_contableFechaRegContableDate à laquelle la facture a été enregistrée dans tes livres comptables. Si absent, utilise tax_point_date puis invoice_date en fallback.
cuota_deducible_in_centsCuotaDeducibleQuote déductible. Quand omis, dérivé de sum(tax_breakdowns.tax_amount). À définir explicitement pour surcharger (déductibilité partielle, etc.).
simplified_art7273FacturaSimplificadaArticulos7.2_7.3Booléen. Même forme qu’Expedida.
reg_previo_ggeeRegPrevioGGEEoREDEMEoCompetenciaBooléen.
macrodataMacrodatoBooléen.
succession_party_*EntidadSucedidaIdentique à Expedida.
billing_agreement_numberNumRegistroAcuerdoFacturacionIdentique à Expedida.
external_referenceRefExternaIdentique à Expedida.

Les deux flags exclusifs à Expedida (facturacion_disp_adicional_mercado_gas, sin_identif_destinatario_art_6_1_d) n’apparaissent pas sur Recibida — le XSD AEAT les définit uniquement sur FacturaExpedidaType.

L’enveloppe XML AEAT est SuministroLRFacturasRecibidas.

Quand supplier_party_country n’est pas es, l’émetteur est rendu comme IDOtro au lieu de NIF :

<sii:IDEmisorFactura>
<sii:IDOtro>
<sii:CodigoPais>FR</sii:CodigoPais>
<sii:IDType>04</sii:IDType>
<sii:ID>FR12345678901</sii:ID>
</sii:IDOtro>
</sii:IDEmisorFactura>

Le bloc Contraparte est également rendu avec IDOtro pour correspondre.


Autres livres (Inversion, Intracomunitaria, Metalico, Seguro, Viajesagencia, Cobro, Pago)

Section titled “Autres livres (Inversion, Intracomunitaria, Metalico, Seguro, Viajesagencia, Cobro, Pago)”

Les sept livres restants couvrent chacun une exigence de déclaration spécifique. Ils partagent les champs CTC communs et le même cycle de vie, mais portent des scalaires spécifiques au livre. Consulte la référence OpenAPI pour la liste complète des champs.

Enregistre la prorata annuelle + la régularisation des biens d’investissement. Enveloppe AEAT : SuministroLRBienesInversion. Champs obligatoires (en plus de l’enveloppe CTC commune) :

  • identificacion_bien — identifiant du bien (IdentificacionBien, max. 40 caractères)
  • fecha_inicio_utilizacion — date à laquelle le bien est entré en service (FechaInicioUtilizacion)
  • prorrata_anual_definitiva — prorata annuelle définitive (ProrrataAnualDefinitiva, 0–100, 2 décimales)

Optionnels : regularizacion_anual_deduccion_in_cents, identificacion_entrega, regularizacion_deduccion_efectuada_in_cents, external_reference, billing_agreement_number, succession_party_*.

Enveloppe AEAT : SuministroLRDetOperacionIntracomunitaria. Obligatoires : clave_declarado (enum D ou R), external_reference (selon le XSD AEAT), plus description mappé à DescripcionBienes. Optionnels : plazo_operacion, facturas_o_documentacion.

Metalico / Seguro / Viajesagencia (agrégés par période)

Section titled “Metalico / Seguro / Viajesagencia (agrégés par période)”

Ces livres sont agrégés par période : un seul enregistrement représente le total d’une contrepartie sur une période fiscale. Il n’y a pas de invoice_number ni de invoice_date — le XSD AEAT omet le bloc IDFactura. La contrepartie est fournie via customer_party_* (B2Brouter la reflète dans nombre_contraparte côté serveur).

  • Metalico : enveloppe SuministroLRCobrosMetalico. Agrège les encaissements en espèces d’une contrepartie ≥ 6 000 € sur une période fiscale.
  • Seguro : enveloppe SuministroLROperacionesSeguros. Ajoute un ClaveOperacion obligatoire mappé depuis operation_type.
  • Viajesagencia : enveloppe SuministroLRAgenciasViajes. Structurellement identique à Metalico selon le XSD AEAT.

Cobro : paiements reçus sur factures émises. Pago : paiements effectués sur factures reçues. Les deux portent un tableau d’événements de paiement par enregistrement dans payload_data :

{
"payload_data": {
"cobros": [
{
"fecha": "2026-03-01",
"importe_in_cents": 50000,
"medio": "01",
"cuenta_o_medio": "ES1234..."
},
{
"fecha": "2026-04-01",
"importe_in_cents": 50000,
"medio": "01",
"cuenta_o_medio": "ES1234..."
}
]
}
}

(Utilise pagos à la place de cobros pour Pago.)

Il n’existe pas de variantes A1 ni B pour ces livres selon le XSD AEAT — PATCH et DELETE retournent 422.


Pour les intégrations à haut volume (agrégations de points de vente, migrations CSV vers JSON, etc.), utilise POST /accounts/{ACCOUNT_ID}/tax_report_batches pour soumettre jusqu’à 5 000 enregistrements en une seule requête. Le traitement est asynchrone : l’appel valide uniquement l’enveloppe et retourne 202 Accepted avec un id de lot ; la construction, la validation et l’attachement au ledger de chaque enregistrement s’exécutent en arrière-plan. Tu dois ensuite interroger l’endpoint de statut du lot (ou te fier au webhook tax_report.state_change par enregistrement une fois que l’AEAT répond).

Terminal window
curl --request POST \
--url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/tax_report_batches' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'Content-Type: application/json' \
--data '{
"tax_reports": [
{ "type": "SiiDocument", "book_type": "Expedida", "invoice_number": "INV-001", ... },
{ "type": "SiiDocument", "book_type": "Expedida", "invoice_number": "INV-002", ... },
...
]
}'

Réponse acceptée (202) :

{
"batch_id": 4567,
"status": "processing",
"total": 2,
"status_url": "https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/tax_report_batches/4567"
}

Interroge le statut du lot sur GET /accounts/{ACCOUNT_ID}/tax_report_batches/{BATCH_ID}. Pendant l’exécution du traitement, status est "processing" ; une fois terminé, il est "done" et results est renseigné, dans l’ordre de soumission :

{
"batch_id": 4567,
"status": "done",
"summary": { "total": 3, "accepted": 2, "rejected": 1 },
"results": [
{ "index": 0, "status": "created", "tax_report": { "id": 12345, ... } },
{ "index": 1, "status": "error", "errors": [{ "code": "invalid_book_type", ... }] },
{ "index": 2, "status": "created", "tax_report": { "id": 12346, ... } }
]
}

Sémantique :

  • Asynchrone : le 202 signifie uniquement que le lot a été accepté pour traitement — pas qu’un enregistrement ait été créé. Interroge status_url jusqu’à ce que status soit "done", ou consomme le webhook tax_report.state_change pour le résultat AEAT de chaque enregistrement créé.
  • Succès partiel : chaque enregistrement est validé indépendamment dans le traitement. Un échec sur un enregistrement (mauvais book_type, XML invalide selon XSD, type non supporté) n’interrompt pas le lot — il apparaît comme error par enregistrement dans results.
  • Erreurs d’enveloppe (clé tax_reports absente, pas un tableau, plus de 5 000 enregistrements) retournent HTTP 400 de manière synchrone, avant que quoi que ce soit soit mis en file d’attente.
  • SII uniquement en v1 : cet endpoint accepte uniquement type: "SiiDocument". Un type non SII ou absent sur un enregistrement est rejeté de manière synchrone avec HTTP 422 (code: "unsupported_type") avant que quoi que ce soit soit mis en file d’attente — c’est une erreur de contrat d’endpoint, distincte des erreurs de données SII par enregistrement (mauvais book_type, XML invalide par XSD), qui sont signalées comme erreurs partielles dans le statut du lot.
  • Attachement au ledger + envoi : les enregistrements créés sont attachés à des ledgers SII ségrégués par mode regroupés par (document_type_code, NIF de l'entreprise déclarante) — c’est-à-dire par le Titular déclaré dans la Cabecera AEAT, pas par le supplier_party_tax_id par enregistrement. Pour Recibida/Pago ce champ contient le fournisseur externe, donc les enregistrements de différents fournisseurs partagent un même ledger tant qu’ils appartiennent au même livre et à la même entreprise déclarante. Les ledgers sont ensuite soumis à l’AEAT par le cron par minute (voir l’API Ledgers) — jamais sur le thread de la requête.

Deux options, utilise l’une ou les deux :

  • Polling sur status_url jusqu’à ce que status soit "done".

  • Webhook — abonne un webhook activé sur ton groupe d’intégration à l’événement sii_batch.finished. Quand le job d’ingestion se termine, B2Brouter envoie un POST :

    {
    "code": "sii_batch.finished",
    "triggered_at": 1748000000,
    "data": {
    "batch_id": 4567,
    "status": "done",
    "summary": { "total": 3, "accepted": 2, "rejected": 1 },
    "status_url": "https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/tax_report_batches/4567"
    }
    }

    Le corps du webhook ne contient que le résumé (borné quelle que soit la taille du lot) ; appelle GET status_url pour les résultats complets par enregistrement. Le résultat AEAT de chaque enregistrement créé arrive toujours via son propre webhook tax_report.state_change.

Les tax reports SII ne sont pas envoyés individuellement à l’AEAT — ils sont regroupés dans des « Libros de Registro » (Ledger dans la terminologie B2Brouter), contenant jusqu’à 5 000 enregistrements par livre / entreprise déclarante (Titular). Chaque tax report a un champ ledger_id pointant vers l’ID interne du Ledger. Avec cet ID tu peux :

Les Ledgers SII modernes sont envoyés à l’AEAT exclusivement par le cron par minute piloté par la politique Strategy::Sii (60 secondes entre les soumissions, ou immédiatement dès qu’un Ledger atteint 5 000 enregistrements). Ni POST /tax_reports, PATCH/DELETE, ni l’endpoint en masse n’envoient jamais à l’AEAT sur le thread de la requête — ils attachent le ou les enregistrement(s) et retournent ; le cron effectue l’envoi. Prévois jusqu’à ~60 s entre la création et la soumission.

Équivalence entre les champs internes de tax report B2Brouter et les nœuds XML du SII

Section titled “Équivalence entre les champs internes de tax report B2Brouter et les nœuds XML du SII”
Champ B2BrouterNœud XML AEAT
fiscal_yearPeriodoLiquidacion > Ejercicio
fiscal_periodPeriodoLiquidacion > Periodo
supplier_party_tax_idIDFactura > IDEmisorFactura > NIF
invoice_numberIDFactura > NumSerieFacturaEmisor
invoice_dateIDFactura > FechaExpedicionFacturaEmisor
invoice_type_codeFacturaExpedida > TipoFactura
tax_point_dateFacturaExpedida > FechaOperacion
special_regime_keyFacturaExpedida > ClaveRegimenEspecialOTrascendencia
billing_agreement_numberFacturaExpedida > NumRegistroAcuerdoFacturacion
tax_inclusive_amountFacturaExpedida > ImporteTotal
descriptionFacturaExpedida > DescripcionOperacion
external_referenceFacturaExpedida > RefExterna
simplified_art7273FacturaExpedida > FacturaSimplificadaArticulos7.2_7.3
succession_party_nameFacturaExpedida > EntidadSucedida > NombreRazon
succession_party_tax_idFacturaExpedida > EntidadSucedida > NIF
reg_previo_ggeeFacturaExpedida > RegPrevioGGEEoREDEMEoCompetencia
macrodataFacturaExpedida > Macrodato
facturacion_disp_adicional_mercado_gasFacturaExpedida > FacturacionDispAdicionalTerceraYsextayDelMercadoOrganizadoDelGas
sin_identif_destinatario_art_6_1_dFacturaExpedida > FacturaSinIdentifDestinatarioAritculo6.1.d
customer_party_nameFacturaExpedida > Contraparte > NombreRazon
customer_party_tax_idFacturaExpedida > Contraparte > NIF
tax_breakdowns[*].percentDetalleIVA > TipoImpositivo
tax_breakdowns[*].taxable_baseDetalleIVA > BaseImponible
tax_breakdowns[*].tax_amountDetalleIVA > CuotaRepercutida (omis quand zéro)
Champ B2BrouterNœud XML AEAT
fiscal_yearPeriodoLiquidacion > Ejercicio
fiscal_periodPeriodoLiquidacion > Periodo
supplier_party_tax_idIDFactura > IDEmisorFactura > NIF (ou IDOtro > ID pour non-ES)
supplier_party_countryIDFactura > IDEmisorFactura > IDOtro > CodigoPais (non-ES seul.)
supplier_party_nameFacturaRecibida > Contraparte > NombreRazon
invoice_numberIDFactura > NumSerieFacturaEmisor
invoice_dateIDFactura > FechaExpedicionFacturaEmisor
invoice_type_codeFacturaRecibida > TipoFactura
tax_point_dateFacturaRecibida > FechaOperacion
special_regime_keyFacturaRecibida > ClaveRegimenEspecialOTrascendencia
billing_agreement_numberFacturaRecibida > NumRegistroAcuerdoFacturacion
tax_inclusive_amountFacturaRecibida > ImporteTotal
descriptionFacturaRecibida > DescripcionOperacion
external_referenceFacturaRecibida > RefExterna
simplified_art7273FacturaRecibida > FacturaSimplificadaArticulos7.2_7.3
succession_party_nameFacturaRecibida > EntidadSucedida > NombreRazon
succession_party_tax_idFacturaRecibida > EntidadSucedida > NIF
reg_previo_ggeeFacturaRecibida > RegPrevioGGEEoREDEMEoCompetencia
macrodataFacturaRecibida > Macrodato
tax_breakdowns[*].percentDetalleIVA > TipoImpositivo
tax_breakdowns[*].taxable_baseDetalleIVA > BaseImponible
tax_breakdowns[*].tax_amountDetalleIVA > CuotaSoportada (omis quand zéro)
fecha_contableFacturaRecibida > FechaRegContable
cuota_deducible_in_centsFacturaRecibida > CuotaDeducible

category de la ventilation fiscale → bucket de desglose

Section titled “category de la ventilation fiscale → bucket de desglose”

Chaque tax_breakdowns[*].category (le code de catégorie de TVA standard PEPPOL/UN-CEFACT) détermine dans quel bucket de desglose de l’AEAT la ligne atterrit. C’est le signal canonique — envoie la bonne category ; les flags booléens en sont dérivés.

Expedida (TipoDesglose > DesgloseFactura) :

categoryBucket AEAT
S, Z, H, AA, AAA, N1 (taxable)Sujeta > NoExenta, TipoNoExenta = S1
AE (autoliquidation)Sujeta > NoExenta, TipoNoExenta = S2
E, K, N2.*, N3.2, N3.6, N4, N5, N7, IC (exonéré)Sujeta > Exenta > DetalleExenta (CausaExencionexemption_code)
NS, O, G, N3.1, N3.3N3.5 (hors champ)NoSujeta (ImporteTAIReglasLocalizacion quand no_subject_code = RL, sinon ImportePorArticulos7_14_Otros)

Un mélange de lignes S1 et S2 se réduit à un unique TipoNoExenta = S3. Une ligne sans catégorie reconnue est rendue comme S1 (entièrement taxable).

Recibida (DesgloseFactura) : les lignes en autoliquidation (category AE) vont dans InversionSujetoPasivo ; tout le reste dans DesgloseIVA.

Pas encore supporté : DesgloseTipoOperacion (la division biens/services que l’AEAT exige pour certaines contreparties transfrontalières). Les factures qui en ont besoin doivent utiliser le chemin CSV hérité jusqu’à ce qu’une version ultérieure ajoute le support — reflète le report de DatosInmueble pour les biens immobiliers.

L’AEAT publie les XSD canoniques du SII. B2Brouter valide le XML généré contre SuministroInformacion.xsd et SuministroLR.xsd (v1.1) à chaque envoi. Les schémas se trouvent dans ce dépôt à vendor/xsd-validator/lib/xsd/schemas/sii_v11/.

Description des codes pour les champs spécifiques

Section titled “Description des codes pour les champs spécifiques”

Les valeurs sont listées dans Qu’est-ce que le SII ? ci-dessus. Le book_type détermine l’enveloppe XML AEAT, l’ensemble des champs obligatoires et les règles de validation.

Pour Expedida et Recibida :

  • F1 — Factura (art. 6, 7.2 y 7.3 del RD 1619/2012)
  • F2 — Factura Simplificada y Facturas sin identificación del destinatario (art. 6.1.d) RD 1619/2012
  • F3 — Factura emitida en sustitución de facturas simplificadas facturadas y declaradas
  • F4 — Asiento resumen de facturas
  • F5 — Importaciones (DUA)
  • F6 — Otros justificantes contables
  • R1 — Factura Rectificativa (Error fundado en derecho y Art. 80 Uno Dos y Seis LIVA)
  • R2 — Factura Rectificativa (Art. 80.3)
  • R3 — Factura Rectificativa (Art. 80.4)
  • R4 — Factura Rectificativa (Resto)
  • R5 — Factura Rectificativa en facturas simplificadas

special_regime_key (ClaveRegimenEspecialOTrascendencia)

Section titled “special_regime_key (ClaveRegimenEspecialOTrascendencia)”

Un code à deux chiffres de l’AEAT décrivant le régime spécial appliqué à l’opération. Les valeurs les plus courantes sont 01 (régimen general), 02 (exportaciones), 03 (régimen especial bienes usados), 04 (régimen especial oro de inversión), 05 (régimen especial agencias de viajes), 06 (régimen especial grupo de entidades), 07 (régimen especial criterio de caja), 08 (operaciones IPSI / IGIC). Consulte les spécifications AEAT pour la liste complète et l’applicabilité par livre.

clave_declarado (Intracomunitaria uniquement)

Section titled “clave_declarado (Intracomunitaria uniquement)”
  • D — Declarante
  • R — Receptor

B2Brouter valide les payloads SII contre les XSD de l’AEAT avant toute soumission. Un échec de validation retourne HTTP 422 avec les champs défaillants détaillés en JSON. Si l’AEAT elle-même rejette une soumission (p. ex. NIF de contrepartie inconnu), le rejet est reflété dans le state de l’enregistrement (typiquement error ou registered_with_errors) et dans les champs error_code / error_description de l’AEAT. Configure le webhook de tax report pour réagir aux états finaux sans polling.