Skip to content
Log in

[Beta] SII-Leitfaden

[Beta] USt-Meldungen an die AEAT über SII (Suministro Inmediato de Información) mit der B2Brouter-API

Section titled “[Beta] USt-Meldungen an die AEAT über SII (Suministro Inmediato de Información) mit der B2Brouter-API”

[Beta] — nur Staging. Die in diesem Leitfaden beschriebene JSON Tax Report API für SII steht derzeit in der Staging-Umgebung (https://api-staging.b2brouter.net) für Integrationstests zur Verfügung. Sie ist noch nicht in der Produktion aktiviert. Feldnamen, Endpunkte und Verhalten können sich vor dem Produktions-Release noch ändern.

Das spanische System Suministro Inmediato de Información (SII) verpflichtet registrierte Unternehmen, ihre USt-Bücher — ausgestellte Rechnungen, empfangene Rechnungen, Investitionsgüter, innergemeinschaftliche Transaktionen, Barzahlungen über 6.000 € und andere — nahezu in Echtzeit an die AEAT („Agencia Estatal de Administración Tributaria”) zu übermitteln. Das SII ist obligatorisch für Grandes Empresas (Umsatz > 6.010.121,04 €), Mitglieder von USt-Gruppen, REDEME-Teilnehmer und andere Unternehmen, die sich freiwillig angemeldet haben.

B2Brouter bietet eine JSON Tax Report API für SII, damit dein System sich nicht mit SOAP, AEAT-Zertifikaten, Batch-Übermittlungen, Antwort-Parsing oder den buchspezifischen XML-Umschlägen befassen muss. Du führst REST-Aufrufe durch; B2Brouter übernimmt den Rest, bündelt die Einträge in AEAT-„Libros de Registro” und übermittelt sie unter einem Zertifikat als Sozialpartner.

Das SII ist ein Steuermeldesystem, das sich von der Rechnungsstellung unterscheidet — die zugrundeliegende Rechnung trägt keinen QR-Code und es gibt keinen verbraucherseitigen Verifizierungsschritt. Jeder Eintrag stellt einen Bucheintrag dar (eine ausgestellte Rechnung, eine empfangene Rechnung, die jährliche Vorsteuerquote eines Investitionsguts usw.). Die AEAT sammelt die Einträge über das Jahr und verwendet sie für USt-Abgleiche.

Das SII hat neun Buchtypen („libros”), jeder mit seinem eigenen AEAT-XML-Umschlag und Validierungsregeln:

BuchtypWas er erfasstA0 (alta)A1 (modificación)B (baja / Stornierung)
ExpedidaAusgestellte Rechnungen
RecibidaEmpfangene Rechnungen
InversionInvestitionsgüter (bienes de inversión)
IntracomunitariaInnergemeinschaftliche Transaktionen
MetalicoBarzahlungen ≥ 6.000 € / Gegenpartei / Zeitraum
SeguroVersicherungsgeschäfte
ViajesagenciaSonderregelung für Reisebüros
CobroEingegangene Zahlungen auf ausgestellte Rechnungen
PagoGeleistete Zahlungen auf empfangene Rechnungen

Cobro und Pago geben HTTP 422 bei PATCH und DELETE zurück — das AEAT-XSD sieht keine A1- oder B-Varianten für diese Bücher vor.

Expedida und Recibida decken 98 %+ des Volumens in der Produktion ab. Die restlichen sieben Bücher unterstützen die breite Palette der USt-Meldepflichten.

Einrichtung und Arbeit mit der B2Brouter-API

Section titled “Einrichtung und Arbeit mit der B2Brouter-API”

Der erste Schritt ist die Aktivierung der SII-Steuerbehörde für das meldende Unternehmen. Den vollständigen Ablauf findest du im Tax Report Settings Guide. Der minimale Aufruf:

Beispielanfrage:

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
}
}'

Sobald eine Konfiguration mit code: "sii" für das Konto vorhanden ist, verwenden alle SII Tax Report API-Aufrufe dieses Kontos diese Konfiguration.

Die Tax Report API ist eine Endpunkt-Familie, die alle neun SII-Bücher verwaltet. Das Buch wird über das Feld book_type im Anfragekörper ausgewählt. Das Feld type ist unabhängig vom Buch für alle SII-Einträge SiiDocument.

POST /accounts/{ACCOUNT_ID}/tax_reports erstellt einen SII-Eintrag. Derselbe Endpunkt wird von Verifactu, TicketBai und KSeF verwendet; das Feld type bestimmt, welcher Validierungssatz + welcher AEAT-XML-Umschlag angewendet wird.

Die Struktur des JSON-Payloads basiert auf dem PEPPOL Continuous Transaction Control (CTC) — die CTC-Feldnamen stimmen nicht mit den AEAT-XML-Knotennamen überein. Der Abschnitt Entsprechung zwischen den internen Tax-Report-Feldern von B2Brouter und den SII-XML-Knoten weiter unten listet das Mapping für jedes Buch auf.

Tax Reports haben Steueraufschlüsselungen („desglose” auf Spanisch), keine Rechnungspositionen. Dein System aggregiert die zugrundeliegenden Rechnungspositionen nach Steuertyp/-kategorie und übermittelt die Summen der Aufschlüsselung. B2Brouter führt die Validierung durch, berechnet aber keine Aufschlüsselungen aus Positionsdaten.

Nach einem erfolgreichen POST /tax_reports enthält die Antwort ein state: "processing" und eine ledger_id. SII-Einträge werden serverseitig in „Libros de Registro” (Ledger) gebündelt und asynchron an die AEAT übermittelt. Um den Lebenszyklus zu verfolgen:

  • Empfohlen: konfiguriere den Tax-Report-Webhook. B2Brouter ruft deinen Endpunkt auf, wenn der Eintrag einen Endzustand erreicht (registered, error, registered_with_errors, annulled oder refused).
  • Polling: rufe GET /tax_reports/{id} wiederholt auf, bis state einen der Endwerte erreicht.

Die AEAT-Antwort wird nach Eingang in drei SII-spezifischen Feldern des Eintrags abgebildet:

  • csv — der von der AEAT zugewiesene Código Seguro de Verificación
  • fecha_presentacion — der von der AEAT zugewiesene Einreichungs-Timestamp
  • estado — der interne SII-Status. Er beginnt bei Nuevo, wechselt zu Enviando während der Übertragung und endet in einem Terminalwert: Correcto, Incorrecto, AceptadoConErrores oder Error.

Bei Fehlerzuständen wird das errors-Array des Eintrags mit der AEAT-Ablehnung gefüllt, wobei jeder Eintrag einen code und eine description enthält:

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

GET /tax_reports/{id}/download gibt das eintragsweise XML zurück, das B2Brouter in die AEAT-Übermittlung einschließen wird (oder eingeschlossen hat). Das XML wird zum Erstellungszeitpunkt generiert und persistiert, ist also unmittelbar nach dem POST verfügbar. Das tatsächlich übertragene Paket ist das zusammengeführte Ledger-XML — siehe Ledger-API.

PATCH /tax_reports/{id} mit den korrigierten Feldern erstellt einen Schwestereintrag mit operacion: A1 (modificación). Der ursprüngliche Eintrag bleibt erhalten; der neue Schwestereintrag wird über corrected_by_id am Original verlinkt und wird erneut an die AEAT übermittelt.

Das Buch, zu dem ein Eintrag gehört, ist zum Erstellungszeitpunkt festgelegt — book_type kann an einem A1-Schwestereintrag nicht geändert werden. Cobro und Pago geben 422 zurück; ihr AEAT-XSD definiert keinen A1-Umschlag.

DELETE /tax_reports/{id} erstellt einen Schwestereintrag mit operacion: B (baja / Stornierung). Das Original wird über annulled_by_id verlinkt. Cobro und Pago geben 422 zurück — ihr AEAT-XSD definiert keinen Baja-Umschlag.

GET /accounts/{ACCOUNT_ID}/tax_reports gibt die Tax Reports des Kontos zurück — SII, Verifactu, TicketBai, KSeF, alle in einer Liste. Filtere nach Datumsbereich oder anderen Kriterien wie im Endpunkt zum Auflisten von Tax Reports dokumentiert.


Das häufigste SII-Buch. Das meldende Unternehmen ist der Rechnungsaussteller; der Kunde ist die Gegenpartei.

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
}
]
}
}'

Expedida-spezifische Felder (zusätzlich zu den gemeinsamen CTC-Feldern):

FeldEntspricht AEAT-ElementHinweise
simplified_art7273FacturaSimplificadaArticulos7.2_7.3Boolescher Wert. Gibt S aus wenn true.
reg_previo_ggeeRegPrevioGGEEoREDEMEoCompetenciaBoolescher Wert.
macrodataMacrodatoBoolescher Wert (SII), anders als die String-Version von Verifactu.
facturacion_disp_adicional_mercado_gasFacturacionDispAdicionalTerceraYsextayDelMercadoOrganizadoDelGasBoolescher Wert. Nur Expedida.
sin_identif_destinatario_art_6_1_dFacturaSinIdentifDestinatarioAritculo6.1.dBoolescher Wert. Nur Expedida.
succession_party_name + _tax_idEntidadSucedida > NombreRazon / NIFBeide gemeinsam erforderlich, wenn verwendet.
billing_agreement_numberNumRegistroAcuerdoFacturacionMax. 15 Zeichen.
external_referenceRefExternaMax. 60 Zeichen.
tax_point_dateFechaOperacionOptional; wird standardmäßig weggelassen.

Der AEAT-XML-Umschlag ist SuministroLRFacturasEmitidas. Die fünf S/N-Flags oben sind optional und werden nur ausgegeben, wenn sie true sind.


Recibida hat die Aussteller/Empfänger-Umkehrung im Vergleich zu Expedida: Der externe Lieferant ist der Aussteller (in IDEmisorFactura erfasst), und das meldende Unternehmen ist der Empfänger (Titular). Verwende supplier_party_* für den externen Lieferanten; customer_party_* ist nicht erforderlich (die Unternehmensstandards werden als Empfänger verwendet).

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
}
]
}
}'

Recibida-spezifische Felder:

FeldEntspricht AEAT-ElementHinweise
supplier_party_tax_id / _nameIDEmisorFactura > NIF / Contraparte > NombreRazonDer externe Lieferant — der Aussteller der empfangenen Rechnung.
supplier_party_countryIDOtro > CodigoPaisWenn nicht es, wird der Aussteller über IDOtro statt NIF ausgegeben.
tax_point_dateFechaOperacionBetriebs-/Leistungsdatum. Wird weggelassen, wenn nicht angegeben.
fecha_contableFechaRegContableDatum, an dem die Rechnung in deinen Büchern erfasst wurde. Wenn nicht vorhanden, wird auf tax_point_date und dann auf invoice_date zurückgefallen.
cuota_deducible_in_centsCuotaDeducibleAbzugsfähige Quote. Wenn weggelassen, wird aus sum(tax_breakdowns.tax_amount) abgeleitet. Explizit setzen zum Überschreiben (Teilabzugsfähigkeit usw.).
simplified_art7273FacturaSimplificadaArticulos7.2_7.3Boolescher Wert. Gleiche Form wie Expedida.
reg_previo_ggeeRegPrevioGGEEoREDEMEoCompetenciaBoolescher Wert.
macrodataMacrodatoBoolescher Wert.
succession_party_*EntidadSucedidaWie Expedida.
billing_agreement_numberNumRegistroAcuerdoFacturacionWie Expedida.
external_referenceRefExternaWie Expedida.

Die beiden Expedida-exklusiven Flags (facturacion_disp_adicional_mercado_gas, sin_identif_destinatario_art_6_1_d) erscheinen nicht in Recibida — das AEAT-XSD definiert sie nur in FacturaExpedidaType.

Der AEAT-XML-Umschlag ist SuministroLRFacturasRecibidas.

Wenn supplier_party_country nicht es ist, wird der Aussteller als IDOtro statt als NIF ausgegeben:

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

Der Contraparte-Block wird ebenfalls mit IDOtro ausgegeben, um zu entsprechen.


Weitere Bücher (Inversion, Intracomunitaria, Metalico, Seguro, Viajesagencia, Cobro, Pago)

Section titled “Weitere Bücher (Inversion, Intracomunitaria, Metalico, Seguro, Viajesagencia, Cobro, Pago)”

Die restlichen sieben Bücher decken jeweils eine spezifische Meldepflicht ab. Sie teilen die gemeinsamen CTC-Felder und denselben Lebenszyklus, tragen aber buchspezifische Skalare. Die vollständige Feldliste findest du in der OpenAPI-Referenz.

Erfasst die jährliche Vorsteuerquote + die Regularisierung von Investitionsgütern. AEAT-Umschlag: SuministroLRBienesInversion. Pflichtfelder (zusätzlich zum gemeinsamen CTC-Umschlag):

  • identificacion_bien — Anlagenkennung (IdentificacionBien, max. 40 Zeichen)
  • fecha_inicio_utilizacion — Datum, an dem das Gut in Betrieb genommen wurde (FechaInicioUtilizacion)
  • prorrata_anual_definitiva — endgültige jährliche Vorsteuerquote (ProrrataAnualDefinitiva, 0–100, 2 Dezimalstellen)

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

Intracomunitaria (innergemeinschaftliche Transaktionen)

Section titled “Intracomunitaria (innergemeinschaftliche Transaktionen)”

AEAT-Umschlag: SuministroLRDetOperacionIntracomunitaria. Pflichtfelder: clave_declarado (Enum D oder R), external_reference (gemäß AEAT-XSD), plus description auf DescripcionBienes abgebildet. Optional: plazo_operacion, facturas_o_documentacion.

Metalico / Seguro / Viajesagencia (zeitraumaggregiert)

Section titled “Metalico / Seguro / Viajesagencia (zeitraumaggregiert)”

Diese Bücher werden zeitraum-aggregiert: Ein einzelner Eintrag repräsentiert den Gesamtbetrag einer Gegenpartei in einem Steuerzeitraum. Es gibt keine invoice_number oder invoice_date — das AEAT-XSD lässt den IDFactura-Block weg. Die Gegenpartei wird über customer_party_* angegeben (B2Brouter spiegelt sie serverseitig in nombre_contraparte).

  • Metalico: Umschlag SuministroLRCobrosMetalico. Aggregiert Barzahlungseingänge einer Gegenpartei ≥ 6.000 € in einem Steuerzeitraum.
  • Seguro: Umschlag SuministroLROperacionesSeguros. Fügt ein obligatorisches ClaveOperacion hinzu, das aus operation_type abgebildet wird.
  • Viajesagencia: Umschlag SuministroLRAgenciasViajes. Strukturell identisch mit Metalico gemäß AEAT-XSD.

Cobro: eingegangene Zahlungen auf ausgestellte Rechnungen. Pago: geleistete Zahlungen auf empfangene Rechnungen. Beide tragen ein Array von Zahlungsereignissen pro Eintrag in 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..."
}
]
}
}

(Verwende pagos statt cobros für Pago.)

Für diese Bücher existieren keine A1- oder B-Varianten gemäß AEAT-XSD — PATCH und DELETE geben 422 zurück.


Für Hochvolumen-Integrationen (Point-of-Sale-Aggregationen, CSV-zu-JSON-Migrationen usw.) verwende POST /accounts/{ACCOUNT_ID}/tax_report_batches, um bis zu 5.000 Einträge in einer einzigen Anfrage zu übermitteln. Die Verarbeitung ist asynchron: Der Aufruf validiert nur den Umschlag und gibt 202 Accepted mit einer Batch-ID zurück; die Erstellung, Validierung und Ledger-Zuweisung jedes Eintrags laufen im Hintergrund. Anschließend musst du den Batch-Status-Endpunkt abfragen (oder den tax_report.state_change-Webhook pro Eintrag nutzen, sobald die AEAT antwortet).

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", ... },
...
]
}'

Akzeptierte Antwort (202):

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

Frage den Batch-Status ab unter GET /accounts/{ACCOUNT_ID}/tax_report_batches/{BATCH_ID}. Während der Verarbeitung ist status "processing"; nach Abschluss ist er "done" und results wird in Übermittlungsreihenfolge gefüllt:

{
"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, ... } }
]
}

Semantik:

  • Asynchron: Die 202 bedeutet nur, dass der Batch zur Verarbeitung akzeptiert wurde — nicht, dass ein Eintrag erstellt wurde. Frage status_url ab, bis status "done" ist, oder konsumiere den tax_report.state_change-Webhook für das AEAT-Ergebnis jedes erstellten Eintrags.
  • Teilerfolg: Jeder Eintrag wird im Job unabhängig validiert. Ein Fehler bei einem Eintrag (falscher book_type, XSD-ungültiges XML, nicht unterstützter type) bricht den Batch nicht ab — er erscheint als error pro Eintrag in results.
  • Umschlags-Fehler (fehlender tax_reports-Key, kein Array, mehr als 5.000 Einträge) geben synchron HTTP 400 zurück, bevor irgendetwas in die Warteschlange gestellt wird.
  • Nur SII in v1: Dieser Endpunkt akzeptiert nur type: "SiiDocument". Ein nicht-SII- oder fehlender type bei einem Eintrag wird synchron mit HTTP 422 abgelehnt (code: "unsupported_type"), bevor irgendetwas in die Warteschlange gestellt wird — das ist ein Endpunkt-Vertragsfehler, anders als SII-Datenfehler pro Eintrag (falscher book_type, XSD-ungültiges XML), die als Teifehler im Batch-Status gemeldet werden.
  • Ledger-Zuweisung + Übermittlung: Erstellte Einträge werden modustrennenden SII-Ledgern zugewiesen, gruppiert nach (document_type_code, Steuer-ID des meldenden Unternehmens) — d.h. nach dem in der AEAT-Cabecera deklarierten Titular, nicht nach dem supplier_party_tax_id pro Eintrag. Für Recibida/Pago enthält dieses Feld den externen Lieferanten, daher teilen Einträge verschiedener Lieferanten einen Ledger, solange sie demselben Buch und meldenden Unternehmen angehören. Ledger werden dann durch den Minuten-Cron an die AEAT übermittelt (siehe Ledger-API) — niemals im Request-Thread.

Zwei Optionen, verwende eine oder beide:

  • Polling auf status_url, bis status "done" ist.

  • Webhook — abonniere einen aktivierten Webhook in deiner Integrationsgruppe für das sii_batch.finished-Event. Wenn der Ingest-Job endet, sendet B2Brouter einen 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"
    }
    }

    Der Webhook-Body enthält nur die Zusammenfassung (begrenzt unabhängig von der Batch-Größe); rufe GET status_url für die vollständigen Ergebnisse pro Eintrag auf. Das AEAT-Ergebnis jedes erstellten Eintrags kommt weiterhin über seinen eigenen tax_report.state_change-Webhook.

SII-Tax-Reports werden nicht einzeln an die AEAT gesendet — sie werden in „Libros de Registro” (Ledger in B2Brouter-Terminologie) gebündelt, mit bis zu 5.000 Einträgen pro Buch / meldendem Unternehmen (Titular). Jeder Tax Report hat ein ledger_id-Feld, das auf die interne Ledger-ID zeigt. Mit dieser ID kannst du:

Moderne SII-Ledger werden ausschließlich durch den Minuten-Cron, gesteuert durch die Strategy::Sii-Policy, an die AEAT übermittelt (60 Sekunden zwischen Übermittlungen, oder sofort sobald ein Ledger 5.000 Einträge erreicht). Weder POST /tax_reports, PATCH/DELETE noch der Massen-Endpunkt senden jemals im Request-Thread an die AEAT — sie weisen den/die Eintrag/Einträge zu und geben zurück; der Cron führt die Übermittlung durch. Plane bis zu ~60 s zwischen Erstellung und Übermittlung ein.

Entsprechung zwischen den internen Tax-Report-Feldern von B2Brouter und den SII-XML-Knoten

Section titled “Entsprechung zwischen den internen Tax-Report-Feldern von B2Brouter und den SII-XML-Knoten”
B2Brouter-FeldAEAT-XML-Knoten
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 (weggelassen wenn null)
B2Brouter-FeldAEAT-XML-Knoten
fiscal_yearPeriodoLiquidacion > Ejercicio
fiscal_periodPeriodoLiquidacion > Periodo
supplier_party_tax_idIDFactura > IDEmisorFactura > NIF (oder IDOtro > ID für Nicht-ES)
supplier_party_countryIDFactura > IDEmisorFactura > IDOtro > CodigoPais (nur Nicht-ES)
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 (weggelassen wenn null)
fecha_contableFacturaRecibida > FechaRegContable
cuota_deducible_in_centsFacturaRecibida > CuotaDeducible

category der Steueraufschlüsselung → Desglose-Bucket

Section titled “category der Steueraufschlüsselung → Desglose-Bucket”

Jede tax_breakdowns[*].category (der Standard-PEPPOL/UN-CEFACT-USt-Kategoriecode) bestimmt, in welchen AEAT-Desglose-Bucket die Zeile fällt. Das ist das kanonische Signal — sende die richtige category; die booleschen Flags werden daraus abgeleitet.

Expedida (TipoDesglose > DesgloseFactura):

categoryAEAT-Bucket
S, Z, H, AA, AAA, N1 (steuerpflichtig)Sujeta > NoExenta, TipoNoExenta = S1
AE (Umkehrung der Steuerschuld)Sujeta > NoExenta, TipoNoExenta = S2
E, K, N2.*, N3.2, N3.6, N4, N5, N7, IC (befreit)Sujeta > Exenta > DetalleExenta (CausaExencionexemption_code)
NS, O, G, N3.1, N3.3N3.5 (nicht steuerbar)NoSujeta (ImporteTAIReglasLocalizacion wenn no_subject_code = RL, sonst ImportePorArticulos7_14_Otros)

Eine Mischung aus S1- und S2-Zeilen kollabiert zu einem einzigen TipoNoExenta = S3. Eine Zeile ohne erkannte Kategorie wird als S1 (vollständig steuerpflichtig) ausgegeben.

Recibida (DesgloseFactura): Zeilen mit Umkehrung der Steuerschuld (category AE) gehen in InversionSujetoPasivo; alles andere in DesgloseIVA.

Noch nicht unterstützt: DesgloseTipoOperacion (die Waren/Dienstleistungen-Aufteilung, die die AEAT für einige grenzüberschreitende Gegenparteien verlangt). Rechnungen, die dies benötigen, sollten den alten CSV-Pfad verwenden, bis eine spätere Version die Unterstützung hinzufügt — entspricht dem Aufschub von DatosInmueble für Immobilien.

Die AEAT veröffentlicht die kanonischen SII-XSDs. B2Brouter validiert das gerenderte XML bei jedem Sendevorgang gegen SuministroInformacion.xsd und SuministroLR.xsd (v1.1). Die Schemata befinden sich in diesem Repository unter vendor/xsd-validator/lib/xsd/schemas/sii_v11/.

Codebeschreibungen für spezifische Felder

Section titled “Codebeschreibungen für spezifische Felder”

Die Werte sind in Was ist das SII? oben aufgelistet. Der book_type bestimmt den AEAT-XML-Umschlag, den Pflichtfeld-Satz und die Validierungsregeln.

Für Expedida und 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)”

Ein zweistelliger AEAT-Code, der das auf die Transaktion angewendete Sonderregime beschreibt. Die häufigsten Werte sind 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). Die vollständige Liste und die Anwendbarkeit pro Buch findest du in den AEAT-Spezifikationen.

  • D — Declarante
  • R — Receptor

B2Brouter validiert SII-Payloads gegen die AEAT-XSDs vor jeder Übermittlung. Ein Validierungsfehler gibt HTTP 422 mit den fehlgeschlagenen Feldern in JSON zurück. Wenn die AEAT selbst eine Übermittlung ablehnt (z.B. unbekannte Gegenpartei-NIF), wird die Ablehnung im state des Eintrags (typischerweise error oder registered_with_errors) und in den Feldern error_code / error_description der AEAT abgebildet. Konfiguriere den Tax-Report-Webhook, um auf Endzustände ohne Polling zu reagieren.