Ir al contenido
Log in

TicketBAI

La Ley Antifraude (Ley 11/2021) y su posterior regulación técnica Real Decreto 1007/2023 obligan a las empresas a garantizar que sus sistemas de facturación y contabilidad cumplan estrictos requisitos técnicos para evitar la manipulación de datos. Para las empresas ubicadas en Euskadi, la Ley Antifraude impone el uso de TicketBAI. La API REST de TicketBAI de B2Brouter es una solución técnica que permite a tu empresa cumplir al 100% la normativa de forma sencilla, delegando las complejidades en B2Brouter y centrándote en la lógica de negocio de tu sistema.

B2Brouter ofrece una cómoda API para presentar informes fiscales TicketBAI, lo que te permite cumplir fácilmente con la legislación de las tres Haciendas Forales del País Vasco (Araba, Bizkaia y Gipuzkoa). Nuestra API abstrae las diferencias entre ellas y te ofrece una interfaz unificada que cumple plenamente con las tres Haciendas Forales. Puedes comprobar el estado de B2Brouter como “software garante” en las tres Haciendas Forales: Araba, Bizkaia, Gipuzkoa.

TicketBAI es un proyecto conjunto de las Diputaciones Forales del País Vasco (Gipuzkoa, Bizkaia y Araba) y el Gobierno Vasco para controlar la facturación y garantizar el cumplimiento fiscal. Exige que todos los autónomos y empresas usen software de facturación certificado que genere un código único y un código QR para cada factura. Este sistema tiene como objetivo prevenir el fraude fiscal garantizando que todas las transacciones económicas se registren y transmitan a las autoridades fiscales en tiempo real o casi real.

TicketBAI implica:

  • Generar un identificador TicketBAI único, un código QR para cada factura y un informe fiscal que incluye la información relevante de la factura.
  • Firmar digitalmente cada informe fiscal usando un certificado electrónico cualificado.
  • Encadenar criptográficamente los informes fiscales para garantizar la inmutabilidad y evitar la manipulación.
  • Presentar el informe fiscal a la Hacienda Foral correspondiente en el formato y plazo especificados.
  • Procesar las respuestas de la Hacienda Foral para cada presentación.

Con B2Brouter puedes abstraer gran parte de las complejidades de este proceso y cumplir con la Ley Antifraude emitiendo solo unas pocas llamadas REST a la API. No necesitarás tu propio certificado electrónico cualificado porque B2Brouter es Colaborador Social en la Gestión Tributaria. Solo necesitas una clave API de B2Brouter válida.

B2Brouter ofrece dos modalidades de operación según si usas B2Brouter tanto para emitir facturas como para reportarlas a la Hacienda Foral, o solo para el reporte fiscal.

Entornos de prueba: Usa el sandbox para las pruebas iniciales de la API y la validación de payloads — el sandbox simula las presentaciones de TicketBAI para que puedas ejercitar el ciclo de vida de la factura sin contactar con la Hacienda Foral del País Vasco. Para pruebas completas de extremo a extremo con el endpoint de pruebas de la autoridad, usa el entorno de staging (api-staging.b2brouter.net).

Configuración y trabajo con la API de B2Brouter

Sección titulada «Configuración y trabajo con la API de B2Brouter»

El primer paso es configurar TicketBAI para cada una de las empresas para las que quieras presentar informes fiscales. Puedes consultar la Guía de Tax Report Settings para una descripción completa del proceso. La llamada para configurar una cuenta es la siguiente:

Ventana de terminal
curl --request GET \
--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": "tbai",
"enabled": true,
"start_date": "2025-04-06",
"auto_generate": true,
"auto_send": true,
"reason_vat_exempt": "E1",
"special_regime_key": "01",
"reason_no_subject": "OT",
"credit_note_code": "R1",
"delegation": "gipuzkoa",
"type_operation": "services"
}
}'

Si usas B2Brouter tanto para emitir facturas como para reportarlas a la Hacienda Foral, una vez que hayas configurado correctamente tu cuenta, puedes operar como lo harías normalmente para emitir facturas.

Las facturas emitidas contendrán el código QR obligatorio, y el informe fiscal TicketBAI se enviará automáticamente a la Hacienda Foral correspondiente. Este es un ejemplo de llamada para crear y emitir una factura:

Ventana de terminal
curl --request POST \
--url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'content-type: application/json' \
--data '{
"send_after_import": true,
"invoice": {
"date": "2025-04-15",
"due_date": "2025-05-15",
"number": 48,
"payment_method": 1,
"contact": {
"name": "Ejemplo S.L.",
"address": "Calle Falsa 123, 3ºA",
"city": "Madrid",
"province": "Madrid",
"postalcode": "28001",
"country": "es",
"email": "john.doe@example.com",
"language": "es",
"currency": "EUR",
"terms": "15",
"payment_method": 1,
"tin_scheme": 9920,
"tin_value": "ESB12345678"
},
"invoice_lines_attributes": [
{
"quantity": 10.0,
"description": "Servicio de Ejemplo",
"price": 11.0,
"unit": 9,
"taxes_attributes": [
{
"name": "IVA",
"percent": 21.0,
"category": "S"
}
]
}
]
}
}'

En la respuesta de la llamada REST POST para crear una factura, si send_after_import está establecido en true, encontrarás una sección tax_report_ids con el ID del informe fiscal asociado a la factura. Ten en cuenta que tax_report_ids es un array porque cada factura puede tener más de un informe fiscal para cancelaciones y correcciones.

Puedes acceder al informe fiscal completo, incluido el código QR, su identificador, su estado y todos los demás campos, llamando al endpoint de obtención de informe fiscal con el ID del informe fiscal proporcionado en la respuesta de la llamada de creación de factura.

El estado del informe fiscal siempre será processing en la respuesta de la llamada POST porque el proceso en segundo plano que encadena y envía el informe fiscal se realiza de forma independiente. Por esta razón debes verificar el ciclo de vida del informe fiscal. Tienes dos opciones:

  • La forma recomendada es usando el webhook de informe fiscal. El webhook emitirá una llamada POST a tu sistema cada vez que el estado del informe fiscal alcance un estado final: registered, error y registered_with_errors

  • Consultar el estado del informe fiscal con el endpoint de obtención de informe fiscal hasta que el campo state sea registered, error o registered_with_errors.

Si no usas B2Brouter para emitir facturas, necesitas más control sobre el proceso de generación y procesamiento de informes fiscales, o esperas un alto volumen de informes fiscales, puedes usar la API de informes fiscales.

La estructura del formato JSON para los informes fiscales de B2Brouter se basa en PEPPOL Continuous Transaction Control (CTC). La API de informes fiscales de B2Brouter es una API universal no solo orientada a TicketBAI sino diseñada para gestionar el reporte fiscal en todo el mundo.

Es importante tener en cuenta que para TicketBAI, los informes fiscales tienen líneas de informe fiscal que representan las líneas individuales de la factura original. El modelo TaxReport no realiza ningún cálculo. Debes proporcionar todas las cifras relevantes en el informe fiscal.

Para crear un informe fiscal debes llamar al endpoint crear informe fiscal. Un informe fiscal mínimo y válido se puede crear con la siguiente llamada POST:

Ventana de terminal
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": "TicketBai",
"invoice_date": "2025-04-03",
"invoice_number": "11",
"description": "Consulting service",
"customer_party_tax_id": "B12345678",
"customer_party_country": "es",
"customer_party_postalcode": "28001",
"customer_party_address": "Calle Falsa 123, 3ºA",
"customer_party_name": "Ejemplo S.L.",
"tax_inclusive_amount": 121.0,
"tax_amount": 21.0,
"invoice_type_code": "F1",
"currency": "EUR",
"tax_report_lines": [
{
"quantity": 1.0,
"description": "Service",
"price": 100.0,
"tax_inclusive_amount": 121.0,
"tax_exclusive_amount": 100.0,
"tax_amount": 21.0
}
],
"tax_breakdowns": [
{
"category": "S",
"non_exempt": true,
"non_exemption_code": "S1",
"percent": 21,
"taxable_base": 100.0,
"tax_amount": 21.0
}
]
}
}'

La respuesta a esta llamada POST devolverá inmediatamente el informe fiscal en estado processing. Los campos qr e identifier serán null inicialmente. Para recuperarlos, realiza peticiones GET posteriores hasta que el state cambie a signed o registered.

El siguiente es un ejemplo más complejo de un TicketBAI con dos líneas, un descuento global, IVA del 21% e IRPF del 15%:

Ventana de terminal
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": "TicketBai",
"invoice_date": "2025-08-13",
"invoice_number": "2025-128",
"description": "Invoice with multiple lines, global discount, IVA, and IRPF (tax withheld)",
"customer_party_tax_id": "B12345678",
"customer_party_country": "es",
"customer_party_postalcode": "28001",
"customer_party_address": "Calle Falsa 123, 3ºA",
"customer_party_name": "Ejemplo S.L.",
"tax_inclusive_amount": 217.8,
"tax_amount": 37.8,
"tax_amount_withheld": 27,
"invoice_type_code": "F1",
"currency": "EUR",
"tax_report_lines": [
{
"quantity": 1,
"description": "Product A",
"price": 100,
"tax_inclusive_amount": 121,
"tax_exclusive_amount": 100,
"tax_amount": 21
},
{
"quantity": 2,
"description": "Product B",
"price": 50,
"tax_inclusive_amount": 121,
"tax_exclusive_amount": 100,
"tax_amount": 21
},
{
"quantity": 1,
"description": "Global Discount 10%",
"price": -20,
"tax_inclusive_amount": -24.2,
"tax_exclusive_amount": -20,
"tax_amount": -4.2
}
],
"tax_breakdowns": [
{
"category": "S",
"non_exempt": true,
"non_exemption_code": "S1",
"percent": 21,
"taxable_base": 180,
"tax_amount": 37.8
}
]
}
}'

Puntos clave a tener en cuenta:

  • Cálculo de impuestos a nivel de línea: TicketBAI exige que todos los impuestos se calculen por línea.
  • Descuentos y cargos globales como líneas: Los descuentos globales deben tratarse como líneas separadas con un price y tax_inclusive_amount negativos.
  • Impuestos retenidos: Los impuestos retenidos (p. ej., IRPF) se reportan a nivel de documento usando el campo tax_amount_withheld.

Debes verificar el ciclo de vida del informe fiscal. Tienes dos opciones:

  • La forma recomendada es usando el webhook de informe fiscal. Los estados finales son: registered, error, annulled y registered_with_errors

  • Consultar el estado del informe fiscal llamando al endpoint de obtención de informe fiscal hasta que el campo state sea alguno de: registered, error, annulled y registered_with_errors.

Obtener la representación XML del informe fiscal

Sección titulada «Obtener la representación XML del informe fiscal»

Si necesitas la representación XML del informe fiscal, usa el endpoint de descarga del informe fiscal. B2Brouter también incluye un campo llamado xml_base64 en la respuesta GET. Ten en cuenta que el XML solo se puede generar después de que el informe fiscal haya sido encadenado (un proceso asíncrono).

B2Brouter ha implementado un exhaustivo conjunto de validaciones de los informes fiscales TicketBAI basado en las especificaciones publicadas por las Haciendas Forales Vascas. Si hay un error de validación, el informe fiscal no se creará. Recibirás una respuesta 422: Unprocessable Entity con todos los errores en formato JSON.

Para cancelar un informe fiscal usa el verbo DELETE llamando al endpoint de anulación. Verifica la evolución de la cancelación procesando el webhook de informe fiscal o consultando el endpoint de obtención de informe fiscal hasta que el campo state del informe fiscal sea error o annulled.

Para listar tus informes fiscales usa el verbo GET en el endpoint de listado de informes fiscales.

Equivalencia entre los campos internos del informe fiscal de B2Brouter y los nodos XML de TicketBAI

Sección titulada «Equivalencia entre los campos internos del informe fiscal de B2Brouter y los nodos XML de TicketBAI»
Campo B2Brouter (basado en PEPPOL CTC)Nodo XML TicketBAI
supplier_party_tax_idSujetos > Emisor > NIF
supplier_party_nameSujetos > Emisor > ApellidosNombreRazonSocial
customer_party_tax_id (si customer_party_tax_scheme es nil)Sujetos > Destinatarios > IDDestinatario > NIF
customer_party_countrySujetos > Destinatarios > IDDestinatario > IDOtro > CodigoPais
customer_party_tax_schemeSujetos > Destinatarios > IDDestinatario > IDOtro > IDType
customer_party_tax_id (si customer_party_tax_scheme está presente)Sujetos > Destinatarios > IDDestinatario > IDOtro > ID
customer_party_nameSujetos > Destinatarios > IDDestinatario > ApellidosNombreRazonSocial
customer_party_postalcodeSujetos > Destinatarios > IDDestinatario > CodigoPostal
customer_party_addressSujetos > Destinatarios > IDDestinatario > Direccion
invoice_series_codeFactura > CabeceraFactura > SerieFactura
invoice_numberFactura > CabeceraFactura > NumFactura
invoice_dateFactura > CabeceraFactura > FechaExpedicionFactura
ticketFactura > CabeceraFactura > FacturaSimplificada
is_amendFactura > CabeceraFactura > FacturaRectificativa
invoice_type_code (si is_amend)Factura > CabeceraFactura > FacturaRectificativa > Codigo
amended_series_codeFactura > CabeceraFactura > FacturasRectificadasSustituidas > IDFacturaRectificadaSustituida > SerieFactura
amended_numberFactura > CabeceraFactura > FacturasRectificadasSustituidas > IDFacturaRectificadaSustituida > NumFactura
amended_dateFactura > CabeceraFactura > FacturasRectificadasSustituidas > IDFacturaRectificadaSustituida > FechaExpedicionFactura
tax_point_dateFactura > DatosFactura > FechaOperacion
descriptionFactura > DatosFactura > DescripcionFactura
tax_report_lines[].descriptionFactura > DatosFactura > DetallesFactura > IDDetalleFactura > DescripcionDetalle
tax_report_lines[].quantityFactura > DatosFactura > DetallesFactura > IDDetalleFactura > Cantidad
tax_report_lines[].priceFactura > DatosFactura > DetallesFactura > IDDetalleFactura > ImporteUnitario
tax_report_lines[].tax_inclusive_amountFactura > DatosFactura > DetallesFactura > IDDetalleFactura > ImporteTotal
tax_inclusive_amountFactura > DatosFactura > ImporteTotalFactura
tax_amount_withheldFactura > DatosFactura > RetencionSoportada
special_regime_keyFactura > DatosFactura > Claves > IDClave > ClaveRegimenIvaOpTrascendencia
tax_breakdowns[].taxable_base (no exento)Factura > TipoDesglose > DesgloseFactura > Sujeta > NoExenta > DetalleNoExenta > DesgloseIVA > DetalleIVA > BaseImponible
tax_breakdowns[].percentFactura > TipoDesglose > DesgloseFactura > Sujeta > NoExenta > DetalleNoExenta > DesgloseIVA > DetalleIVA > TipoImpositivo
tax_breakdowns[].tax_amountFactura > TipoDesglose > DesgloseFactura > Sujeta > NoExenta > DetalleNoExenta > DesgloseIVA > DetalleIVA > CuotaImpuesto

Esquemas TicketBAI proporcionados por las Haciendas Forales Vascas.

Archivo XSDDescripción
ticketbaiv1-2-2.xsdEsquema principal de TicketBAI
anula_ticketbaiv1-2-2.xsdEsquema para el suministro de facturas

Descripciones de códigos para campos específicos

Sección titulada «Descripciones de códigos para campos específicos»

Parámetro: invoice_type_code

CódigoDescripción
F1Factura (art. 6, 7.2 y 7.3 del RD 1619/2012)
F2Factura Simplificada y Facturas sin identificación del destinatario (art. 6.1.d) RD 1619/2012
F3Factura emitida en sustitución de facturas simplificadas facturadas y declaradas
R1Factura Rectificativa (Error fundado en derecho y Art. 80 Uno Dos y Seis LIVA)
R2Factura Rectificativa (Art. 80.3)
R3Factura Rectificativa (Art. 80.4)
R4Factura Rectificativa (Resto)
R5Factura Rectificativa en facturas simplificadas

Parámetro: special_regime_key

CódigoDescripción
01Operación de régimen general.
02Exportación.
03Operaciones a las que se aplique el régimen especial de bienes usados, objetos de arte, antigüedades y objetos de colección.
04Régimen especial del oro de inversión.
05Régimen especial de las agencias de viajes.
06Régimen especial grupo de entidades en IVA (Nivel Avanzado)
07Régimen especial del criterio de caja.
08Operaciones sujetas al IPSI / IGIC.
51Operaciones en recargo de equivalencia.
52Operaciones en régimen simplificado.

Parámetro: non_exemption_code

CódigoDescripción
S1Operación Sujeta y No exenta - Sin inversión del sujeto pasivo.
S2Operación Sujeta y No exenta - Con Inversión del sujeto pasivo.

Parámetro: exemption_code

CódigoDescripción
E1Exenta por el artículo 20
E2Exenta por el artículo 21
E3Exenta por el artículo 22
E4Exenta por los artículos 23 y 24
E5Exenta por el artículo 25
E6Exenta por otros

Parámetro: no_subject_code

CódigoDescripción
OTNo sujeto por el artículo 7 de la Norma Foral de IVA Otros supuestos de no sujeción.
RLNo sujeto por reglas de localización.
VTNo sujeto, ventas realizadas por cuenta de terceros.
IENo sujeto en el TAI por reglas de localización, pero repercute impuesto extranjero.

Parámetro: customer_party_tax_scheme

CódigoDescripción
02NIF-IVA de la UE
03Pasaporte
04Documento de identidad oficial emitido por el país de residencia
05Certificado de residencia
06Otro documento acreditativo