Ejemplos

Ejemplos de la API TicketBAI: el JSON de cada tipo de factura

Los tipos de factura que emite un TPV o un ERP en Euskadi, con el JSON que envías a KubiBAI en cada caso. En cada ejemplo hemos resaltado lo que cambia respecto a los demás.

Antes de empezar

Lo que tienen en común todas las peticiones

Cambia el cuerpo JSON de una factura a otra, pero la forma de llamar a la API es siempre la misma.

  • POST /invoicing/invoices envía una factura. La URL base es wstests.kubibai.com/api en pruebas y kws.kubibai.net/api en producción.
  • X-Qbikode-ClientApiKey lleva la API key de la empresa emisora, y Content-Type y Accept van con application/json.
  • sender_data identifica a la empresa emisora. sender_ticketbai_territory_id sale de la consulta de territorios de la API.
  • Los importes van en céntimos y los precios y cantidades con decimales implícitos: quantity: 100 es 1,00 unidad y tax_rate: 2100 es el 21 %.
  • Los importes, los números y los NIF son ficticios, los mismos que usa la documentación.

La respuesta, con el estado, el identificador TBAI y el QR, la tienes en cómo funciona. Las anulaciones, Zuzendu, los reenvíos y el LROE de Bizkaia tienen sus propios endpoints en la documentación (abre en nueva pestaña). Si lo que buscas es el paso a paso para cada tipo de software, mira TicketBAI para TPV y TicketBAI para ERP y SaaS.

Facturas ordinarias

El caso base: una factura completa entre empresas, a un cliente español o extranjero.

Factura básica

Una factura ordinaria de 121,00 € de una empresa de Gipuzkoa: un servicio de 100,00 € con IVA del 21 %, a otra empresa.

  • sender_data identifica al emisor por su NIF y su territorio; tienen que coincidir con la empresa de la X-Qbikode-ClientApiKey.
  • local_subject_not_exempt_items lleva el desglose del IVA: base, tax_rate (2100 es el 21 %) y cuota.
  • previous_invoice_data encadena con la factura anterior; puedes omitirlo si activas el encadenamiento automático desde el panel web.
  • Los importes van en céntimos: total_amount: 12100 son 121,00 €.
Ver este ejemplo en la documentación (abre en nueva pestaña)
POST /invoicing/invoices
{  "sender_data": {    "sender_ticketbai_territory_id": "dded8ad1-0574-4ee4-b4f7-36687cba73b9",    "sender_is_individual": false,    "sender_full_name": "Empresa Ejemplo S.L.",    "sender_id_card_number": "B12345674"  },  "recipients": [    {      "tax_id_number": "B76543214",      "full_name": "Cliente Ejemplo S.A.",      "postal_code": "20004",      "address": "Avenida de la Libertad 1"    }  ],  "invoice_data": {    "fiscal_year": 2026,    "series_code": "A",    "invoice_number": "2026-002",    "invoice_datetime": "2026-07-22 10:30:00",    "description": "Servicio de consultoría",    "total_amount": 12100,    "vat_keys": [      {        "transaction_of_tax_significance_code": "01"      }    ],    "concepts": [      {        "description": "Servicio de consultoría",        "quantity": 100,        "unit_price": 10000000000,        "total_price": 12100      }    ],    "local_subject_not_exempt_items": [      {        "vat_not_exempt_type": "S1",        "vat_breakdown_items": [          {            "taxable_amount": 10000,            "tax_rate": 2100,            "tax_quota": 2100          }        ]      }    ]  },  "previous_invoice_data": {    "signature_value": "firma-ficticia-factura-2026-001",    "series_code": "A",    "invoice_number": "2026-001",    "invoice_date": "2026-07-21"  }}

Factura a un cliente extranjero

Un servicio de consultoría a una empresa alemana, no sujeto a IVA por las reglas de localización.

  • El destinatario no lleva tax_id_number: se identifica con other_id_country_code, other_id_type (02 es NIF-IVA) y other_id_card_id.
  • foreign_services_not_subject_items con la causa RL marca la operación como no sujeta; no se combina con un desglose local de IVA.
Ver este ejemplo en la documentación (abre en nueva pestaña)
POST /invoicing/invoices
{  "sender_data": {    "sender_ticketbai_territory_id": "dded8ad1-0574-4ee4-b4f7-36687cba73b9",    "sender_is_individual": false,    "sender_full_name": "Empresa Ejemplo S.L.",    "sender_id_card_number": "B12345674"  },  "recipients": [    {      "full_name": "Empresa extranjera de prueba",      "other_id_country_code": "DE",      "other_id_type": "02",      "other_id_card_id": "DE123456789",      "postal_code": "10117",      "address": "Musterstraße 1, Berlín"    }  ],  "invoice_data": {    "fiscal_year": 2026,    "series_code": "A",    "invoice_number": "2026-003",    "invoice_datetime": "2026-07-22 11:00:00",    "description": "Servicio de consultoría",    "total_amount": 10000,    "vat_keys": [      {        "transaction_of_tax_significance_code": "01"      }    ],    "concepts": [      {        "description": "Servicio de consultoría",        "quantity": 100,        "unit_price": 10000000000,        "total_price": 10000      }    ],    "foreign_services_not_subject_items": [      {        "cause_code": "RL",        "amount": 10000      }    ]  },  "previous_invoice_data": {    "signature_value": "firma-ficticia-factura-2026-002",    "series_code": "A",    "invoice_number": "2026-002",    "invoice_date": "2026-07-22"  }}

Facturas simplificadas

El ticket de un TPV y la factura completa que puede pedir el cliente después.

Factura simplificada

Una venta en mostrador de 60,50 € sin identificar al destinatario.

  • is_simplified_invoice: true permite omitir recipients; no mandes un array vacío ni datos ficticios.
  • No es el régimen simplificado de IVA: no actives is_equalization_or_simplified_operation por ser una simplificada.
  • En Gipuzkoa, concepts es obligatorio también en las simplificadas.
Ver este ejemplo en la documentación (abre en nueva pestaña)
POST /invoicing/invoices
{  "sender_data": {    "sender_ticketbai_territory_id": "dded8ad1-0574-4ee4-b4f7-36687cba73b9",    "sender_is_individual": false,    "sender_full_name": "Empresa Ejemplo S.L.",    "sender_id_card_number": "B12345674"  },  "invoice_data": {    "fiscal_year": 2026,    "series_code": "A",    "invoice_number": "2026-004",    "invoice_datetime": "2026-07-22 11:30:00",    "is_simplified_invoice": true,    "description": "Venta en mostrador",    "total_amount": 6050,    "vat_keys": [      {        "transaction_of_tax_significance_code": "01"      }    ],    "concepts": [      {        "description": "Venta en mostrador",        "quantity": 100,        "unit_price": 5000000000,        "total_price": 6050      }    ],    "local_subject_not_exempt_items": [      {        "vat_not_exempt_type": "S1",        "vat_breakdown_items": [          {            "taxable_amount": 5000,            "tax_rate": 2100,            "tax_quota": 1050          }        ]      }    ]  },  "previous_invoice_data": {    "signature_value": "firma-ficticia-factura-2026-003",    "series_code": "A",    "invoice_number": "2026-003",    "invoice_date": "2026-07-22"  }}

Sustitución de factura simplificada

La factura completa que se emite cuando el cliente de un ticket pide una factura con sus datos.

  • issued_in_substitution_of_simplified: true indica que sustituye a una simplificada, e replaced_rectified_invoices dice cuál.
  • Es una factura completa, así que lleva recipients.
  • No es una rectificativa: no incluyas rectificative_reason_code ni los campos rectified_*.
Ver este ejemplo en la documentación (abre en nueva pestaña)
POST /invoicing/invoices
{  "sender_data": {    "sender_ticketbai_territory_id": "dded8ad1-0574-4ee4-b4f7-36687cba73b9",    "sender_is_individual": false,    "sender_full_name": "Empresa Ejemplo S.L.",    "sender_id_card_number": "B12345674"  },  "recipients": [    {      "tax_id_number": "B76543214",      "full_name": "Cliente Ejemplo S.A.",      "postal_code": "20004",      "address": "Avenida de la Libertad 1"    }  ],  "invoice_data": {    "fiscal_year": 2026,    "series_code": "A",    "invoice_number": "2026-005",    "invoice_datetime": "2026-07-22 12:00:00",    "issued_in_substitution_of_simplified": true,    "replaced_rectified_invoices": [      {        "series_code": "A",        "invoice_number": "2026-004",        "invoice_date": "2026-07-22"      }    ],    "description": "Venta en mostrador",    "total_amount": 6050,    "vat_keys": [      {        "transaction_of_tax_significance_code": "01"      }    ],    "concepts": [      {        "description": "Venta en mostrador",        "quantity": 100,        "unit_price": 5000000000,        "total_price": 6050      }    ],    "local_subject_not_exempt_items": [      {        "vat_not_exempt_type": "S1",        "vat_breakdown_items": [          {            "taxable_amount": 5000,            "tax_rate": 2100,            "tax_quota": 1050          }        ]      }    ]  },  "previous_invoice_data": {    "signature_value": "firma-ficticia-factura-2026-004",    "series_code": "A",    "invoice_number": "2026-004",    "invoice_date": "2026-07-22"  }}

Facturas rectificativas

Dos formas de corregir la misma factura. Eliges una, no las dos.

Rectificativa por sustitución

Corrige el precio de una factura: la base debió ser de 80,00 € y no de 100,00 €. La nueva factura trae los importes correctos.

  • rectificative_type_code: "S" indica que los importes correctos sustituyen a los originales.
  • rectified_base_amount y rectified_quota llevan la base y la cuota originales; el desglose y total_amount, los nuevos.
  • replaced_rectified_invoices identifica la factura que se corrige, y previous_invoice_data la anterior de la cadena. Son cosas distintas.
Ver este ejemplo en la documentación (abre en nueva pestaña)
POST /invoicing/invoices
{  "sender_data": {    "sender_ticketbai_territory_id": "dded8ad1-0574-4ee4-b4f7-36687cba73b9",    "sender_is_individual": false,    "sender_full_name": "Empresa Ejemplo S.L.",    "sender_id_card_number": "B12345674"  },  "recipients": [    {      "tax_id_number": "B76543214",      "full_name": "Cliente Ejemplo S.A.",      "postal_code": "20004",      "address": "Avenida de la Libertad 1"    }  ],  "invoice_data": {    "fiscal_year": 2026,    "series_code": "A",    "invoice_number": "2026-006",    "invoice_datetime": "2026-07-22 12:30:00",    "rectificative_reason_code": "R4",    "rectificative_type_code": "S",    "rectified_base_amount": 10000,    "rectified_quota": 2100,    "replaced_rectified_invoices": [      {        "series_code": "A",        "invoice_number": "2026-002",        "invoice_date": "2026-07-22"      }    ],    "description": "Corrección del precio del servicio de consultoría",    "total_amount": 9680,    "vat_keys": [      {        "transaction_of_tax_significance_code": "01"      }    ],    "concepts": [      {        "description": "Servicio de consultoría",        "quantity": 100,        "unit_price": 8000000000,        "total_price": 9680      }    ],    "local_subject_not_exempt_items": [      {        "vat_not_exempt_type": "S1",        "vat_breakdown_items": [          {            "taxable_amount": 8000,            "tax_rate": 2100,            "tax_quota": 1680          }        ]      }    ]  },  "previous_invoice_data": {    "signature_value": "firma-ficticia-factura-2026-005",    "series_code": "A",    "invoice_number": "2026-005",    "invoice_date": "2026-07-22"  }}

Rectificativa por diferencias

La misma corrección, registrando solo la diferencia: −20,00 € de base, −4,20 € de cuota y −24,20 € de total.

  • rectificative_type_code: "I": el desglose lleva únicamente la diferencia, con importes negativos.
  • No incluyas rectified_base_amount ni rectified_quota.
Ver este ejemplo en la documentación (abre en nueva pestaña)
POST /invoicing/invoices
{  "sender_data": {    "sender_ticketbai_territory_id": "dded8ad1-0574-4ee4-b4f7-36687cba73b9",    "sender_is_individual": false,    "sender_full_name": "Empresa Ejemplo S.L.",    "sender_id_card_number": "B12345674"  },  "recipients": [    {      "tax_id_number": "B76543214",      "full_name": "Cliente Ejemplo S.A.",      "postal_code": "20004",      "address": "Avenida de la Libertad 1"    }  ],  "invoice_data": {    "fiscal_year": 2026,    "series_code": "A",    "invoice_number": "2026-006",    "invoice_datetime": "2026-07-22 12:30:00",    "rectificative_reason_code": "R4",    "rectificative_type_code": "I",    "replaced_rectified_invoices": [      {        "series_code": "A",        "invoice_number": "2026-002",        "invoice_date": "2026-07-22"      }    ],    "description": "Corrección del precio del servicio de consultoría",    "total_amount": -2420,    "vat_keys": [      {        "transaction_of_tax_significance_code": "01"      }    ],    "concepts": [      {        "description": "Diferencia del servicio de consultoría",        "quantity": 100,        "unit_price": -2000000000,        "total_price": -2420      }    ],    "local_subject_not_exempt_items": [      {        "vat_not_exempt_type": "S1",        "vat_breakdown_items": [          {            "taxable_amount": -2000,            "tax_rate": 2100,            "tax_quota": -420          }        ]      }    ]  },  "previous_invoice_data": {    "signature_value": "firma-ficticia-factura-2026-005",    "series_code": "A",    "invoice_number": "2026-005",    "invoice_date": "2026-07-22"  }}

Bizkaia y administraciones públicas

Dos casos con reglas propias: el modelo 140 de las entidades de Bizkaia y la factura TicketBAI con FacturaE.

Comunidad de bienes en Bizkaia (modelo 140)

Una factura emitida por una comunidad de bienes de Bizkaia, que se tramita por el modelo 140.

  • Las entidades con NIF que empieza por E (comunidades de bienes), J (sociedades civiles) o H (comunidades de propietarios) envían sender_is_individual: true.
  • income_data_items es obligatorio en el modelo 140 y describe la actividad y la renta; admite hasta diez elementos.
  • En Bizkaia, concepts puede omitirse. No lo traslades a Araba ni a Gipuzkoa.
Ver este ejemplo en la documentación (abre en nueva pestaña)
POST /invoicing/invoices
{  "sender_data": {    "sender_ticketbai_territory_id": "b4039144-5069-4584-88e1-7086c9f01adc",    "sender_is_individual": true,    "sender_full_name": "Comunidad de Bienes Ejemplo C.B.",    "sender_id_card_number": "E12345674"  },  "recipients": [    {      "tax_id_number": "B76543214",      "full_name": "Cliente Ejemplo S.A."    }  ],  "invoice_data": {    "fiscal_year": 2026,    "series_code": "CB",    "invoice_number": "2026-001",    "invoice_datetime": "2026-07-22 13:00:00",    "description": "Servicios de mantenimiento",    "total_amount": 12100,    "vat_keys": [      {        "transaction_of_tax_significance_code": "01"      }    ],    "local_subject_not_exempt_items": [      {        "vat_not_exempt_type": "S1",        "vat_breakdown_items": [          {            "taxable_amount": 10000,            "tax_rate": 2100,            "tax_quota": 2100          }        ]      }    ]  },  "income_data_items": [    {      "epigraph": "197330",      "is_different_taxable_income": false,      "uses_collection_criteria": false    }  ]}

TicketBAI y FacturaE para una administración pública

Una sola petición genera la factura TicketBAI, que KubiBAI firma y envía, y el XML FacturaE 3.2.1 para la administración.

  • generate_facturae: true devuelve el XML FacturaE en Base64 (facturae_xml_contents). KubiBAI no lo envía a FACe: eso lo gestionas tú.
  • administrative_centers lleva los códigos DIR3 que te facilita la administración destinataria.
  • Con FacturaE, concepts pasa a ser obligatorio incluso en Bizkaia.
Ver este ejemplo en la documentación (abre en nueva pestaña)
POST /invoicing/invoices
{  "sender_data": {    "sender_ticketbai_territory_id": "b4039144-5069-4584-88e1-7086c9f01adc",    "sender_is_individual": false,    "sender_full_name": "Empresa Consultora Ejemplo S.L.",    "sender_id_card_number": "B12345674",    "sender_address": "Gran Vía de Don Diego López de Haro 1",    "sender_postal_code": "48001",    "sender_town": "Bilbao",    "sender_province": "Bizkaia"  },  "recipients": [    {      "tax_id_number": "P1234567D",      "full_name": "Ayuntamiento de Ejemplo",      "postal_code": "48002",      "address": "Plaza del Ayuntamiento 1",      "is_legal_entity": true,      "town": "Municipio de Ejemplo",      "province": "Bizkaia",      "facturae_country_code": "ESP",      "administrative_centers": [        {          "role": "01",          "code": "L01234567",          "name": "Oficina Contable de Ejemplo",          "address": "Plaza del Ayuntamiento 1",          "postal_code": "48002",          "town": "Municipio de Ejemplo",          "province": "Bizkaia",          "facturae_country_code": "ESP"        },        {          "role": "02",          "code": "L01234568",          "name": "Órgano Gestor de Ejemplo",          "address": "Plaza del Ayuntamiento 1",          "postal_code": "48002",          "town": "Municipio de Ejemplo",          "province": "Bizkaia",          "facturae_country_code": "ESP"        },        {          "role": "03",          "code": "L01234569",          "name": "Unidad Tramitadora de Ejemplo",          "address": "Plaza del Ayuntamiento 1",          "postal_code": "48002",          "town": "Municipio de Ejemplo",          "province": "Bizkaia",          "facturae_country_code": "ESP"        }      ]    }  ],  "invoice_data": {    "fiscal_year": 2026,    "series_code": "FAC",    "invoice_number": "2026-001",    "invoice_datetime": "2026-07-22 15:00:00",    "description": "Servicios de consultoría técnica",    "total_amount": 12100,    "vat_keys": [      {        "transaction_of_tax_significance_code": "01"      }    ],    "concepts": [      {        "description": "Servicios de consultoría técnica",        "quantity": 100,        "unit_price": 10000000000,        "total_price": 12100,        "vat_rate": 2100      }    ],    "local_subject_not_exempt_items": [      {        "vat_not_exempt_type": "S1",        "vat_breakdown_items": [          {            "taxable_amount": 10000,            "tax_rate": 2100,            "tax_quota": 2100          }        ]      }    ]  },  "generate_facturae": true,  "async_mode": "none"}

Dudas habituales

Preguntas sobre los ejemplos

¿Cambia el cuerpo de la petición según el territorio?

Sí. La estructura cambia según el territorio, el tipo de emisor, los destinatarios y el desglose fiscal. Por ejemplo, concepts es obligatorio en Araba y Gipuzkoa y puede omitirse en Bizkaia, salvo que generes también FacturaE. Cada ejemplo indica a qué caso corresponde.

¿Cómo envío el ticket de un TPV?

Con is_simplified_invoice: true y sin recipients. Si después el cliente pide una factura con sus datos, se emite una factura completa con issued_in_substitution_of_simplified: true e replaced_rectified_invoices con la simplificada que sustituye.

¿Qué diferencia hay entre una rectificativa por sustitución y por diferencias?

Por sustitución (rectificative_type_code S) la nueva factura lleva los importes correctos, y rectified_base_amount y rectified_quota recogen la base y la cuota originales. Por diferencias (I) solo se registra la diferencia, con importes negativos, y esos dos campos no se incluyen. Eliges una de las dos, no ambas.

¿Cómo indico la factura anterior de la cadena?

En previous_invoice_data, con el signature_value de la factura anterior. Si KubiBAI lo reconoce, completa serie, número y fecha; si no, hay que enviar los cuatro campos. Puedes omitirlo si es la primera factura de la cadena o si has activado el encadenamiento automático de la empresa o del TPV, que es opcional y se activa desde el panel web.

¿Cómo envío una factura a un cliente extranjero?

Sin tax_id_number: el destinatario lleva other_id_country_code, other_id_type y other_id_card_id. Si es un servicio no sujeto por reglas de localización, se usa foreign_services_not_subject_items con la causa RL, sin combinarlo con un desglose local de IVA.

¿Puedo probar estos ejemplos tal cual?

Los valores son ficticios y los mismos de la documentación. Para enviarlos necesitas la API key de una empresa dada de alta en el entorno de pruebas, y el NIF y el territorio del emisor tienen que coincidir con los de esa empresa. Las facturas de pruebas se remiten a los servidores de pruebas de TicketBAI.

Empieza hoy

Conecta tu software con TicketBAI

Pídenos acceso al entorno de pruebas, integra con la documentación y pasa a producción cuando todo encaje.