VeriBaiDocs
Acceder

Facturas y registros

Los endpoints de lectura. Estado, detalle, QR, XML firmado y listados.

La remisión a Hacienda es asíncrona. Estos endpoints permiten seguir cada factura hasta su estado final y recuperar sus artefactos: el QR, el XML firmado y el historial de registros. Base URL: https://sandbox.veribai.com (TEST) o https://api.veribai.com (LIVE).

Método Endpoint Descripción
GET /v1/facturas Listado de facturas de un emisor.
GET /v1/facturas/buscar Localiza una factura por serie, número y fecha. Recupera su idFactura.
GET /v1/facturas/{idFactura} Detalle completo de una factura.
GET /v1/facturas/{idFactura}/estado Estado actual (polling).
GET /v1/facturas/{idFactura}/qr QR de la factura (PNG binario).
GET /v1/facturas/{idFactura}/xml XML firmado del registro.
GET /v1/registros Listado de registros de facturación de un emisor.
GET /v1/registros/{idRegistro} Detalle de un registro.

{idFactura} es el idFactura que devuelve el alta. Todas las lecturas requieren el parámetro nifEmisor (el NIF del emisor) y verifican que pertenece a tu cuenta; un emisor ajeno devuelve 403.

GET /v1/facturas

GET/v1/facturas?nifEmisor=B98765432&limite=100

curl "https://sandbox.veribai.com/v1/facturas?nifEmisor=B98765432&limite=100" \
  -H "x-api-key: TU_CLAVE"
Parámetro Notas
nifEmisor Obligatorio. NIF del emisor cuyas facturas quieres listar.
fechaInicio / fechaFin Opcionales. Acotan por fecha de registro, en ISO 8601.
estado Opcional. Filtro por ciclo de vida: registrada, anulada o rectificada.
sistemaFiscal Opcional: verifactu o ticketbai.
limite Opcional, por defecto 100, máximo 500. Un valor por encima del máximo se recorta a 500; uno no entero o menor que 1 responde 400 INVALID_PARAMETER. ?limite= vacío usa el valor por defecto.
cursor Opcional. Cursor de paginación: el proximaPagina de la página anterior.
{
  "facturas": [
    {
      "idFactura": "…",
      "nifEmisor": "B98765432",
      "numeroFactura": "A12345",
      "tipoFactura": "F1",
      "importeTotal": "121.00",
      "cuotaTotal": "21.00",
      "sistemaFiscal": "verifactu",
      "estadoFactura": "registrada",
      "fechaRegistro": "2026-04-03T10:01:03Z",
      "ultimaModificacion": "2026-04-03T10:01:03Z",
      "urlQr": "https://…",
      "hashVerifactu": "…",
      "csvAeat": "…"
    }
  ],
  "total": 15,
  "nifEmisor": "B98765432",
  "nombreEmisor": "Restaurant La Buena Mesa SL",
  "proximaPagina": null
}

proximaPagina trae el cursor de la página siguiente; null significa que no hay más páginas. Los campos sin valor se omiten, y filtros aparece solo cuando la petición incluyó algún filtro.

GET /v1/facturas/{idFactura}/estado

El endpoint de polling: mínimo, estable y pensado para consultarse de forma diferida.

GET/v1/facturas/ID_FACTURA/estado?nifEmisor=B98765432

curl "https://sandbox.veribai.com/v1/facturas/ID_FACTURA/estado?nifEmisor=B98765432" \
  -H "x-api-key: TU_CLAVE"

Mientras la remisión está en curso, la respuesta trae el estado del envío:

{
  "idFactura": "…",
  "numeroFactura": "A12345",
  "estadoEnvio": "en_cola",
  "estadoFactura": null,
  "sistemaFiscal": "ticketbai",
  "ultimaModificacion": "2026-04-03T10:00:12Z"
}

Cuando la administración acepta el registro, estadoFactura toma el relevo:

{
  "idFactura": "…",
  "numeroFactura": "A12345",
  "estadoFactura": "registrada",
  "csvAeat": "…",
  "sistemaFiscal": "verifactu",
  "ultimaModificacion": "2026-04-03T10:01:03Z"
}
Campo Notas
estadoEnvio Estado de la remisión en curso: pendiente_proceso, pendiente_envio, en_lote, en_cola, rechazada… (desconocido si el registro no informa estado). Presente mientras la factura no está registrada.
estadoFactura Estado de la factura ya registrada: registrada, anulada o rectificada. null mientras la remisión no ha concluido.
csvAeat VeriFactu: el CSV que la AEAT asigna al registro aceptado.

Un estadoEnvio de rechazada sin estadoFactura significa rechazo. Consulta el detalle y actúa según el caso: rectificar o subsanar.

Si prefieres no sondear, los webhooks llaman a tu servidor cuando la factura alcanza su desenlace: registrada, rechazada o anulada.

GET /v1/facturas/{idFactura} (detalle)

Devuelve la factura completa: datos de emisión, estado, artefactos y trazabilidad, en el sobre { "factura": {…}, "registros": […], "totalRegistros": N }. Los campos concretos dependen del sistema (VeriFactu o TicketBAI) y del estado; mientras la factura sigue en proceso, la vista mínima devuelve estadoFactura: "procesando". Requiere ?nifEmisor=.

GET /v1/facturas/buscar

Localiza una factura a partir de la identidad que ya tienes (serie, número y fecha de expedición) cuando has perdido su idFactura. Sin ese identificador quedas fuera también de /estado, /qr, /xml y /registros.

GET/v1/facturas/buscar?nifEmisor=B98765432&serie=A&numero=12&fechaExpedicion=15-01-2026

curl "https://sandbox.veribai.com/v1/facturas/buscar?nifEmisor=B98765432&serie=A&numero=12&fechaExpedicion=15-01-2026" \
  -H "x-api-key: TU_CLAVE"
Parámetro Notas
nifEmisor Obligatorio. NIF del emisor.
numero Obligatorio. El número de factura sin la serie.
fechaExpedicion Obligatorio. dd-mm-aaaa, con dos dígitos en día y mes.
serie Opcional. Omítelo si la factura se emitió sin serie.

Devuelve el mismo sobre que el detalle ({ "factura": {…}, "registros": […], "totalRegistros": N }), así que la respuesta trae el idFactura y con él vuelves a tener acceso a /estado, /qr, /xml y /registros.

serie y numero van separados, nunca unidos. El campo numeroFactura de las respuestas es la concatenación de ambos: serie=A&numero=12 y serie=A1&numero=2 se leen igual ahí (A12), pero son facturas distintas. Si envías la concatenación en numero, la búsqueda no encuentra nada y el 404 resulta inexplicable.

Error Cuándo
400 MISSING_PARAMETER Falta numero o fechaExpedicion.
400 VALIDATION_ERROR fechaExpedicion mal formada: 15/01/2026 y 2026-01-15 se rechazan; el formato es 15-01-2026. También si serie o numero superan 60 caracteres.
404 NOT_FOUND Ninguna factura de ese emisor tiene esa identidad.

Los 400 nombran el parámetro culpable en campo.

QR y XML

GET /v1/facturas/{idFactura}/qr?nifEmisor=…    →  image/png
GET /v1/facturas/{idFactura}/xml?nifEmisor=…   →  application/xml

Envía Accept: image/png al pedir el QR. Con el */* que mandan por defecto la mayoría de clientes HTTP, el cuerpo llega como el texto base64 del PNG aunque la respuesta siga anunciándose como image/png, y escribirlo a un fichero produce una imagen que no abre. El cliente de Python manda siempre la cabecera.

El QR también llega en base64 en la respuesta del alta (qrBase64). Este endpoint lo sirve como binario para regeneraciones. El XML firmado es el documento con valor probatorio remitido a la administración: descargable en cualquier momento para auditoría o custodia propia.

El QR se genera en cada petición a partir de la URL de validación que la factura lleva guardada, no se recupera de un almacén de imágenes: es idéntico al qrBase64 que devolvió el alta y está disponible para cualquier factura emitida, sin caducidad.

Ambas rutas responden 404 NOT_FOUND cuando la factura existe pero su documento no está disponible: en /xml, que el documento no está almacenado; en /qr, que la factura no tiene URL de validación, lo que es una anomalía y no un caso corriente.

GET /v1/registros

Facturas y registros son recursos distintos. La factura es la operación; el registro documenta cada remisión: el alta y, si los hubo, su subsanación o anulación. Ver El registro de facturación.

GET/v1/registros?nifEmisor=B98765432

curl "https://sandbox.veribai.com/v1/registros?nifEmisor=B98765432" \
  -H "x-api-key: TU_CLAVE"
Parámetro Notas
nifEmisor Obligatorio. NIF del emisor.
limite / cursor Paginación, como en /v1/facturas: por defecto 100, máximo 500, con las mismas reglas de validación.

Devuelve los registros de alta y de anulación ordenados por fecha de creación descendente, en el sobre { "registros": […], "total", "nifEmisor", "nombreEmisor", "proximaPagina" }.

Campo Notas
idRegistro Identificador opaco del registro. Es lo que se envía de vuelta en la ruta del detalle. Para distinguir un alta de una anulación, el campo es tipo.
tipo alta, subsanacion o anulacion.
estado Estado del registro: pendiente al crearse, procesando mientras una corrección VeriFactu está en curso, y aceptada o rechazada al concluir.
estadoEnvio Estado de la remisión mientras está en curso: pendiente_proceso, pendiente_envio, en_lote, en_cola (desconocido si el registro no informa estado).
estadoEnvioFinal El veredicto de la administración: registrada o rechazada. Aparece al concluir la remisión; a partir de ese momento estadoEnvio deja de ser informativo.
codigoRespuestaAeat / descripcionRespuestaAeat El código y la descripción que devolvió la administración. En un rechazo, el motivo. El código viaja como cadena ("1286"), nunca como número. Compáralo como texto.
csvAeat VeriFactu: el CSV asignado al registro aceptado.
creadoEn / envioCompletadoEn Cuándo se creó el registro y cuándo concluyó su remisión.
idLote Lote de envío, cuando el registro viajó agrupado.
idMaquina Presente cuando el envío lo indicó.

En TicketBAI se añaden tipoRespuestaTbai, codigoRespuestaTbai, mensajeRespuestaTbai, idRegistroTbai y provincia.

GET /v1/registros/{idRegistro} devuelve el detalle de un registro concreto. Requiere ?nifEmisor= y ?idFactura= (la factura a la que pertenece el registro), y añade a los campos anteriores cuotaTotal, sistemaFiscal, ultimaModificacion, esRectificativa, tipoRectificativa y, en los registros de anulación, fechaExpedicion, sinRegistroPrevio y rechazoPrevio.

GET/v1/registros/UkVDIzIwMjYtMDgtMjRUMDg6Mjk6MzZa?nifEmisor=B98765432&idFactura=ID_FACTURA

curl "https://sandbox.veribai.com/v1/registros/UkVDIzIwMjYtMDgtMjRUMDg6Mjk6MzZa?nifEmisor=B98765432&idFactura=ID_FACTURA" \
  -H "x-api-key: TU_CLAVE"

El idRegistro es opaco

Llega en el listado de registros y en el detalle de la factura, y vuelve tal cual: sin recortarlo, sin normalizarlo y sin codificarlo para la URL. No lo interpretes ni lo construyas, y no supongas nada sobre su longitud ni sobre su alfabeto. Su forma es interna y puede cambiar. Guárdalo como una cadena, del mismo modo que el cursor de paginación. Un identificador que no se reconoce responde 400 INVALID_PARAMETER.

La forma anterior, con prefijo REC# o CNC#, ya no se devuelve ni se acepta. Si leías ese prefijo para saber ante qué registro estabas, el campo que lo dice es tipo.

Cómo leer un rechazo

Un registro con estadoEnvioFinal: "rechazada" no ha quedado presentado ante la administración. El motivo está en codigoRespuestaAeat y descripcionRespuestaAeat (en TicketBAI, además, en codigoRespuestaTbai y mensajeRespuestaTbai). Son el código y el texto de la propia administración.

Corrige el dato que señalan y reenvía con PUT /v1/{sistema}/subsanar. VeriBai no reintenta por su cuenta un rechazo por datos: el mismo envío obtendría el mismo rechazo, y en TicketBAI cada intento avanza la cadena de huellas del emisor de forma permanente.

Para no sondear en busca de rechazos, suscríbete al evento factura.rechazada de los webhooks: llega con el código de la administración en el cuerpo.