Factuarea API

Estados de envío VeriFactu

El ciclo de vida de un registro de facturación VeriFactu — pending, submitted, accepted, rejected, error —, qué significan el CSV y la huella, cómo funciona el presupuesto de reintentos y cuándo reintentar en lugar de subsanar.

Cada factura que emite tu empresa bajo VeriFactu produce un registro de facturación: una declaración XML firmada que se transmite a la AEAT y queda encadenada criptográficamente al registro anterior de la misma empresa. La factura y su registro son dos objetos distintos con dos ciclos de vida distintos — una factura puede estar sent y cobrada mientras su registro sigue rejected por la AEAT.

Esta página trata del registro. Si integras contra Factuarea y solo vigilas el estado de la factura, no te enterarás de que la Administración tributaria rechazó una declaración.

Cuándo aplica

El ciclo de vida del registro aplica a toda empresa con VeriFactu efectivamente activado, desde el momento en que una factura sale de draft. No aplica a:

  • Empresas todavía en modo no_verifactu: los registros se siguen creando y encadenando en local, pero nunca se transmiten, así que quedan fuera del ciclo aceptado/rechazado (BR-VFC-018, RD 1007/2023 art. 16).
  • Facturas históricas importadas saltándose el paso de VeriFactu — no se crea registro alguno, de modo que no hay nada que consultar (BR-VFC-009).

Consulta Alta automática en VeriFactu para las compuertas que deciden si el registro llega a crearse.

Los cinco estados

statusSignificado¿Terminal?Qué haces
pendingEl registro existe y está encadenado, pero aún no se ha transmitido.NoNada. La transmisión está en cola.
submittedEnviado a la AEAT, a la espera de la respuesta definitiva.NoNada. Consultar.
acceptedLa AEAT registró la declaración. aeat_csv viene informado.Sí — inmutableNada. Para corregir la factura, emite una rectificativa.
rejectedLa AEAT lo rechazó por un error de datos (NIF del destinatario desconocido, esquema, totales).Respuesta definitiva, pero reparableCorrige los datos y luego subsanar.
errorFallo técnico de transmisión: timeout, AEAT inaccesible, problema de firma.NoNada, o forzar un retry.

La distinción que importa es rejected frente a error. rejected es la AEAT diciendo «he leído tu declaración y está mal». error es la declaración que nunca llegó. Se reparan con operaciones distintas, y confundirlas es el error de integración más habitual en este endpoint.

accepted es el único estado genuinamente inmutable: la matriz de transiciones rechaza cualquier salida de él, porque el RD 1007/2023 hace inalterable un registro ya registrado. Todos los demás estados admiten una nueva transición, y eso es lo que hace posibles el reintento y la subsanación.

Qué envía la API

Nunca creas un registro con un payload — se crea por ti. Lo que haces es leerlo. La API v1 devuelve el objeto registro en GET /v1/verifactu/records/{id}, GET /v1/verifactu/records y, indexado por factura, en GET /v1/invoices/{id}/verifactu:

CampoSignificado
statusUno de los cinco estados de arriba.
typeALTA (la factura se emitió) o ANULACION (se anuló).
invoice_typeEl tipo de factura AEAT congelado en el momento de emitir: F1, F2, F3, R1R5.
huellaLa huella SHA-256 de este registro, en hexadecimal mayúsculas. Es el eslabón al que apuntará el registro siguiente.
aeat_csvEl Código Seguro de Verificación que devuelve la AEAT al aceptar. Vale null hasta entonces. Es el valor con el que concilias contra la Administración tributaria.
aeat_submission_idNuestro identificador de transmisión, para conversaciones con soporte.
transmitted_atISO 8601 de la última transmisión que llegó a la AEAT. Viene informado en submitted y accepted; vale null en pending, rejected y error.
environmentEl entorno AEAT de esta empresa — producción o el entorno de pruebas de la AEAT. Un CSV obtenido en pruebas no es un alta real.
is_simplificada / is_substitute_for_simplifiedSi la factura de origen era una F2, y si este registro sustituye facturas simplificadas mediante una F3.

Dos campos merecen su propio aviso.

La huella es identidad, no una suma de control que puedas recalcular. Se calcula a partir del NIF del emisor, la serie y el número, la fecha de expedición, el tipo de factura, la cuota total, el importe total, la huella del registro anterior y la marca de tiempo de generación — en ese orden y formato exactos. Si cualquiera de esos valores cambia, la cadena se rompe y falla la prueba de integridad de toda la empresa (BR-VFC-013). Por eso hay correcciones que no se pueden reparar en el sitio; ver Reintentar o subsanar.

El aeat_csv se escribe una sola vez. Al aceptarse se persiste y nunca se sobrescribe, ni siquiera si la AEAT devuelve el mismo CSV en una transmisión posterior. Un registro que pasa a rejected después de haber estado submitted conserva el CSV anterior a efectos de auditoría, así que un aeat_csv no nulo en un registro rejected es lo esperado, no un fallo (BR-VFC-016).

curl https://api.factuarea.com/v1/invoices/0197a2a8-4cf0-7a31-9a5e-3f2b8c1d6e42/verifactu \
  -H "Authorization: Bearer fact_live_3pXnR2VbY7TcA9eFmN5z8KqW"
{
  "data": {
    "id": "0197b3c9-1de2-7c40-8b71-a4d5e6f70123",
    "object": "verifactu_record",
    "type": "ALTA",
    "invoice_type": "F1",
    "invoice_number": "F-2026-0042",
    "date": "2026-05-15",
    "amount": 121.0,
    "status": "accepted",
    "huella": "9F2C1A0B7E4D6835A1C0B9E8D7F6A5B43C2D1E0F9A8B7C6D5E4F3A2B1C0D9E8F",
    "aeat_submission_id": "sub_0197b3c9",
    "aeat_csv": "FCT-2026-A1B2C3D4-E5F6",
    "environment": "production",
    "transmitted_at": "2026-05-15T09:41:02Z",
    "is_simplificada": false,
    "is_substitute_for_simplified": false,
    "created_at": "2026-05-15T09:40:58Z"
  }
}

El presupuesto de reintentos existe, y no viaja en el payload

Detrás de error hay un contador y una planificación. Una transmisión fallida se vuelve a encolar con retroceso exponencial, y el número de reintentos técnicos a ciegas está topado por ronda de transmisión; agotado el tope, un reintento manual adicional responde con un error de regla de negocio en lugar de volver a encolar (BR-VFC-006). Junto al contador, el registro lleva una marca de incidencia técnica, que se levanta cuando fue la propia AEAT la que estuvo inaccesible y hubo que declarar la incidencia — se conserva incluso tras una aceptación posterior, a efectos de auditoría.

Ninguno de esos tres valores — el contador de intentos, el siguiente reintento programado y la marca de incidencia — se expone en el objeto registro de la v1. Gobiernan el comportamiento que observas, pero hoy no puedes leerlos por la API pública. Lo que puedes observar es el estado en sí, transmitted_at y la cronología de auditoría del registro vía GET /v1/verifactu/records/{id}/activities. No construyas en tu cliente un modelo adivinado de la planificación de reintentos: consulta el estado.

Reintentar o subsanar

Ambas operaciones actúan sobre un registro que ya existe. No son intercambiables.

Estado del registroCausaOperaciónPor qué
errorLa declaración nunca llegó a la AEAT.POST /v1/verifactu/records/{id}/retryEl XML almacenado es correcto. Se reenvía sin cambios.
rejectedLa AEAT lo leyó y rechazó los datos.POST /v1/verifactu/records/{id}/subsanarHay que regenerar el XML a partir de los datos maestros corregidos.
acceptedNinguna.El registro es inmutable. Emite una factura rectificativa.
rejected, pero la corrección toca un campo de la huellaSe declaró mal el total, la fecha, el número, el NIF o el tipo de factura.Ninguna — anular y volver a emitir.Cambiar un campo de la huella invalidaría la cadena. subsanar lo rechaza de entrada.

Reintentar a ciegas consume el presupuesto de reintentos técnicos. La subsanación no: es una corrección manual deliberada con datos nuevos, la norma no le pone tope y ejecutarla reinicia la ronda de transmisión — el contador de intentos vuelve a cero y la retransmisión automática del contenido corregido recupera su presupuesto íntegro (BR-VFC-006, BR-VFC-020).

La subsanación regenera el payload pero incrusta la huella original, el eslabón de cadena original y la marca de tiempo de generación original, porque son los que permiten a la AEAT casar el reenvío con el registro que rechazó. Antes de persistir nada compara los campos regenerados que entran en la huella con los almacenados; si alguno difiere, responde 422 con el subcódigo que te indica que hace falta anular, y no se modifica nada. El flujo completo, los subcódigos de error y los consejos de prevención están en Subsanación de registros VeriFactu.

Qué sale en el PDF

El estado del registro no cambia el PDF. Sea cual sea el estado, la factura imprime el mismo bloque QR legal en la esquina superior derecha de la primera página: la etiqueta QR tributario:, un código de 30×30 mm que apunta al servicio de verificación de la AEAT con el NIF del emisor, la serie y el número, la fecha y el total, y la leyenda debajo (BR-VFC-015).

Tres consecuencias que conviene contemplar en el diseño:

  • El QR se imprime en cuanto existe un registro — incluso mientras está pending, error o rejected. Un destinatario que lo escanee antes de la aceptación verá que la AEAT no informa de ningún alta. Es el comportamiento correcto, no un defecto.
  • El CSV no se imprime en el PDF. Solo está disponible por la API y en el panel.
  • La huella y la marca de tiempo del alta también dejaron de imprimirse. Si los estabas extrayendo del PDF, léelos del registro.

La subsanación es la única operación que además toca el documento impreso: vuelve a congelar deliberadamente los snapshots inmutables de destinatario y emisor a partir de los datos maestros actuales, para que el PDF coincida con lo que se volvió a declarar a la AEAT (BR-INV-024, BR-VFC-020). Es el único camino que reescribe un snapshot ya congelado.

Qué llega a la AEAT

Cada registro transmite una declaración, encadenada por su huella al registro anterior de la misma empresa. Existen tres clases de registro, y no comparten una sola cadena: las altas (ALTA) y las anulaciones (ANULACION) comparten la cadena de facturación, mientras que los registros de eventos del sistema mantienen una cadena propia aparte, porque la norma trata los eventos operativos como evidencia separada (BR-VFC-014).

Cuando un reenvío sigue a un rechazo, la declaración regenerada lleva además las marcas AEAT que declaran que el envío anterior fue rechazado y que, por tanto, el registro nunca llegó a registrarse. Ninguna de las dos entra en el cálculo de la huella, así que declararlas no perturba la cadena (BR-VFC-026).

Puedes verificar la cadena entera por tu cuenta con GET /v1/verifactu/chain/validate, que recalcula todas las huellas e informa de las anomalías. Está limitado a una llamada por minuto y empresa porque recorre el libro registro completo.

Trazabilidad

Derivado de las reglas de dominio del backend de Factuarea:

  • BR-VFC-006 — política de reintentos: retroceso exponencial, intentos topados por ronda, y el tope que explícitamente no aplica a la subsanación.
  • BR-VFC-013 — la cadena de huellas es inmutable y verificable; cualquier alteración invalida la garantía de integridad ante la AEAT.
  • BR-VFC-014 — las tres clases de registro y sus cadenas independientes.
  • BR-VFC-015 — el bloque QR obligatorio en la factura impresa.
  • BR-VFC-016 — el CSV como identidad pública del registro, persistido sin alterar.
  • BR-VFC-018 — modo no_verifactu: cadena local, sin transmisión.
  • BR-VFC-020 — subsanación de registros rechazados, guarda de la huella y reinicio de la ronda de transmisión.
  • BR-VFC-026 — las marcas AEAT para un reenvío tras rechazo.
  • BR-INV-024 — el snapshot inmutable del destinatario y la única excepción que lo refresca.

Derivado también de la máquina de estados de transmisión documentada junto a esas reglas (AeatTransmissionStatus), que es la fuente de verdad de la matriz de transiciones citada en Los cinco estados.

En esta página