[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.
Was ist das SII?
Section titled “Was ist das SII?”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:
| Buchtyp | Was er erfasst | A0 (alta) | A1 (modificación) | B (baja / Stornierung) |
|---|---|---|---|---|
| Expedida | Ausgestellte Rechnungen | ✓ | ✓ | ✓ |
| Recibida | Empfangene Rechnungen | ✓ | ✓ | ✓ |
| Inversion | Investitionsgüter (bienes de inversión) | ✓ | ✓ | ✓ |
| Intracomunitaria | Innergemeinschaftliche Transaktionen | ✓ | ✓ | ✓ |
| Metalico | Barzahlungen ≥ 6.000 € / Gegenpartei / Zeitraum | ✓ | ✓ | ✓ |
| Seguro | Versicherungsgeschäfte | ✓ | ✓ | ✓ |
| Viajesagencia | Sonderregelung für Reisebüros | ✓ | ✓ | ✓ |
| Cobro | Eingegangene Zahlungen auf ausgestellte Rechnungen | ✓ | — | — |
| Pago | Geleistete 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:
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.
Tax Report API
Section titled “Tax Report API”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.
Einen Tax Report erstellen
Section titled “Einen Tax Report erstellen”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.
Lebenszyklus
Section titled “Lebenszyklus”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,annulledoderrefused). - Polling: rufe
GET /tax_reports/{id}wiederholt auf, bisstateeinen 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ónfecha_presentacion— der von der AEAT zugewiesene Einreichungs-Timestampestado— der interne SII-Status. Er beginnt beiNuevo, wechselt zuEnviandowährend der Übertragung und endet in einem Terminalwert:Correcto,Incorrecto,AceptadoConErroresoderError.
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" } ]}Die XML-Darstellung abrufen
Section titled “Die XML-Darstellung abrufen”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.
Einen Tax Report korrigieren (A1)
Section titled “Einen Tax Report korrigieren (A1)”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.
Einen Tax Report stornieren (B)
Section titled “Einen Tax Report stornieren (B)”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.
Tax Reports auflisten
Section titled “Tax Reports auflisten”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.
Expedida (ausgestellte Rechnungen)
Section titled “Expedida (ausgestellte Rechnungen)”Das häufigste SII-Buch. Das meldende Unternehmen ist der Rechnungsaussteller; der Kunde ist die Gegenpartei.
Beispielanfrage
Section titled “Beispielanfrage”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):
| Feld | Entspricht AEAT-Element | Hinweise |
|---|---|---|
simplified_art7273 | FacturaSimplificadaArticulos7.2_7.3 | Boolescher Wert. Gibt S aus wenn true. |
reg_previo_ggee | RegPrevioGGEEoREDEMEoCompetencia | Boolescher Wert. |
macrodata | Macrodato | Boolescher Wert (SII), anders als die String-Version von Verifactu. |
facturacion_disp_adicional_mercado_gas | FacturacionDispAdicionalTerceraYsextayDelMercadoOrganizadoDelGas | Boolescher Wert. Nur Expedida. |
sin_identif_destinatario_art_6_1_d | FacturaSinIdentifDestinatarioAritculo6.1.d | Boolescher Wert. Nur Expedida. |
succession_party_name + _tax_id | EntidadSucedida > NombreRazon / NIF | Beide gemeinsam erforderlich, wenn verwendet. |
billing_agreement_number | NumRegistroAcuerdoFacturacion | Max. 15 Zeichen. |
external_reference | RefExterna | Max. 60 Zeichen. |
tax_point_date | FechaOperacion | Optional; 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 (empfangene Rechnungen)
Section titled “Recibida (empfangene Rechnungen)”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).
Beispielanfrage
Section titled “Beispielanfrage”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:
| Feld | Entspricht AEAT-Element | Hinweise |
|---|---|---|
supplier_party_tax_id / _name | IDEmisorFactura > NIF / Contraparte > NombreRazon | Der externe Lieferant — der Aussteller der empfangenen Rechnung. |
supplier_party_country | IDOtro > CodigoPais | Wenn nicht es, wird der Aussteller über IDOtro statt NIF ausgegeben. |
tax_point_date | FechaOperacion | Betriebs-/Leistungsdatum. Wird weggelassen, wenn nicht angegeben. |
fecha_contable | FechaRegContable | Datum, 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_cents | CuotaDeducible | Abzugsfähige Quote. Wenn weggelassen, wird aus sum(tax_breakdowns.tax_amount) abgeleitet. Explizit setzen zum Überschreiben (Teilabzugsfähigkeit usw.). |
simplified_art7273 | FacturaSimplificadaArticulos7.2_7.3 | Boolescher Wert. Gleiche Form wie Expedida. |
reg_previo_ggee | RegPrevioGGEEoREDEMEoCompetencia | Boolescher Wert. |
macrodata | Macrodato | Boolescher Wert. |
succession_party_* | EntidadSucedida | Wie Expedida. |
billing_agreement_number | NumRegistroAcuerdoFacturacion | Wie Expedida. |
external_reference | RefExterna | Wie 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.
Nicht-spanische Lieferanten
Section titled “Nicht-spanische Lieferanten”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.
Inversion (Investitionsgüter)
Section titled “Inversion (Investitionsgüter)”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 obligatorischesClaveOperacionhinzu, das ausoperation_typeabgebildet wird. - Viajesagencia: Umschlag
SuministroLRAgenciasViajes. Strukturell identisch mit Metalico gemäß AEAT-XSD.
Cobro / Pago (Zahlungsverfolgung)
Section titled “Cobro / Pago (Zahlungsverfolgung)”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.
Massen-Endpunkt (asynchron)
Section titled “Massen-Endpunkt (asynchron)”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).
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
202bedeutet nur, dass der Batch zur Verarbeitung akzeptiert wurde — nicht, dass ein Eintrag erstellt wurde. Fragestatus_urlab, bisstatus"done"ist, oder konsumiere dentax_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ütztertype) bricht den Batch nicht ab — er erscheint alserrorpro Eintrag inresults. - Umschlags-Fehler (fehlender
tax_reports-Key, kein Array, mehr als 5.000 Einträge) geben synchron HTTP400zurück, bevor irgendetwas in die Warteschlange gestellt wird. - Nur SII in v1: Dieser Endpunkt akzeptiert nur
type: "SiiDocument". Ein nicht-SII- oder fehlendertypebei einem Eintrag wird synchron mit HTTP422abgelehnt (code: "unsupported_type"), bevor irgendetwas in die Warteschlange gestellt wird — das ist ein Endpunkt-Vertragsfehler, anders als SII-Datenfehler pro Eintrag (falscherbook_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-Cabeceradeklarierten Titular, nicht nach demsupplier_party_tax_idpro 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.
Wissen, wann der Batch abgeschlossen ist
Section titled “Wissen, wann der Batch abgeschlossen ist”Zwei Optionen, verwende eine oder beide:
-
Polling auf
status_url, bisstatus"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_urlfür die vollständigen Ergebnisse pro Eintrag auf. Das AEAT-Ergebnis jedes erstellten Eintrags kommt weiterhin über seinen eigenentax_report.state_change-Webhook.
Ledger-API
Section titled “Ledger-API”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:
- Die XML-Darstellung des Ledgers über den Ledger-Download-Endpunkt abrufen. Das ist das Dokument, das B2Brouter an die AEAT sendet.
- Die AEAT-XML-Antwort auf diesen Ledger über den Antwort-Download-Endpunkt abrufen.
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”Expedida (SuministroLRFacturasEmitidas)
Section titled “Expedida (SuministroLRFacturasEmitidas)”| B2Brouter-Feld | AEAT-XML-Knoten |
|---|---|
fiscal_year | PeriodoLiquidacion > Ejercicio |
fiscal_period | PeriodoLiquidacion > Periodo |
supplier_party_tax_id | IDFactura > IDEmisorFactura > NIF |
invoice_number | IDFactura > NumSerieFacturaEmisor |
invoice_date | IDFactura > FechaExpedicionFacturaEmisor |
invoice_type_code | FacturaExpedida > TipoFactura |
tax_point_date | FacturaExpedida > FechaOperacion |
special_regime_key | FacturaExpedida > ClaveRegimenEspecialOTrascendencia |
billing_agreement_number | FacturaExpedida > NumRegistroAcuerdoFacturacion |
tax_inclusive_amount | FacturaExpedida > ImporteTotal |
description | FacturaExpedida > DescripcionOperacion |
external_reference | FacturaExpedida > RefExterna |
simplified_art7273 | FacturaExpedida > FacturaSimplificadaArticulos7.2_7.3 |
succession_party_name | FacturaExpedida > EntidadSucedida > NombreRazon |
succession_party_tax_id | FacturaExpedida > EntidadSucedida > NIF |
reg_previo_ggee | FacturaExpedida > RegPrevioGGEEoREDEMEoCompetencia |
macrodata | FacturaExpedida > Macrodato |
facturacion_disp_adicional_mercado_gas | FacturaExpedida > FacturacionDispAdicionalTerceraYsextayDelMercadoOrganizadoDelGas |
sin_identif_destinatario_art_6_1_d | FacturaExpedida > FacturaSinIdentifDestinatarioAritculo6.1.d |
customer_party_name | FacturaExpedida > Contraparte > NombreRazon |
customer_party_tax_id | FacturaExpedida > Contraparte > NIF |
tax_breakdowns[*].percent | DetalleIVA > TipoImpositivo |
tax_breakdowns[*].taxable_base | DetalleIVA > BaseImponible |
tax_breakdowns[*].tax_amount | DetalleIVA > CuotaRepercutida (weggelassen wenn null) |
Recibida (SuministroLRFacturasRecibidas)
Section titled “Recibida (SuministroLRFacturasRecibidas)”| B2Brouter-Feld | AEAT-XML-Knoten |
|---|---|
fiscal_year | PeriodoLiquidacion > Ejercicio |
fiscal_period | PeriodoLiquidacion > Periodo |
supplier_party_tax_id | IDFactura > IDEmisorFactura > NIF (oder IDOtro > ID für Nicht-ES) |
supplier_party_country | IDFactura > IDEmisorFactura > IDOtro > CodigoPais (nur Nicht-ES) |
supplier_party_name | FacturaRecibida > Contraparte > NombreRazon |
invoice_number | IDFactura > NumSerieFacturaEmisor |
invoice_date | IDFactura > FechaExpedicionFacturaEmisor |
invoice_type_code | FacturaRecibida > TipoFactura |
tax_point_date | FacturaRecibida > FechaOperacion |
special_regime_key | FacturaRecibida > ClaveRegimenEspecialOTrascendencia |
billing_agreement_number | FacturaRecibida > NumRegistroAcuerdoFacturacion |
tax_inclusive_amount | FacturaRecibida > ImporteTotal |
description | FacturaRecibida > DescripcionOperacion |
external_reference | FacturaRecibida > RefExterna |
simplified_art7273 | FacturaRecibida > FacturaSimplificadaArticulos7.2_7.3 |
succession_party_name | FacturaRecibida > EntidadSucedida > NombreRazon |
succession_party_tax_id | FacturaRecibida > EntidadSucedida > NIF |
reg_previo_ggee | FacturaRecibida > RegPrevioGGEEoREDEMEoCompetencia |
macrodata | FacturaRecibida > Macrodato |
tax_breakdowns[*].percent | DetalleIVA > TipoImpositivo |
tax_breakdowns[*].taxable_base | DetalleIVA > BaseImponible |
tax_breakdowns[*].tax_amount | DetalleIVA > CuotaSoportada (weggelassen wenn null) |
fecha_contable | FacturaRecibida > FechaRegContable |
cuota_deducible_in_cents | FacturaRecibida > 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):
category | AEAT-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 (CausaExencion ← exemption_code) |
NS, O, G, N3.1, N3.3–N3.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 vonDatosInmueblefür Immobilien.
XSD-Dateien
Section titled “XSD-Dateien”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”book_type
Section titled “book_type”Die Werte sind in Was ist das SII? oben aufgelistet. Der book_type bestimmt den AEAT-XML-Umschlag, den Pflichtfeld-Satz und die Validierungsregeln.
invoice_type_code
Section titled “invoice_type_code”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/2012F3— Factura emitida en sustitución de facturas simplificadas facturadas y declaradasF4— Asiento resumen de facturasF5— Importaciones (DUA)F6— Otros justificantes contablesR1— 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.
clave_declarado (nur Intracomunitaria)
Section titled “clave_declarado (nur Intracomunitaria)”D— DeclaranteR— Receptor
Fehlerprüfung
Section titled “Fehlerprüfung”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.