Subsanación de registros VeriFactu
Corrige un registro de facturación VeriFactu —rechazado o aceptado por la AEAT— con un registro NUEVO que lo sucede. Cuándo aplica la subsanación, cuándo necesitas una anulación o una rectificativa y el flujo exacto de la API.
Cuando la AEAT rechaza un registro de facturación VeriFactu por un error de
datos (registro con status: rejected), o cuando un registro aceptado resulta
llevar datos erróneos para los que las reglas de facturación no exigen una factura
rectificativa, la normativa VeriFactu (Real Decreto 1007/2023, art. 11) te permite
subsanarlo. La AEAT no admite una edición en su sitio: la corrección es siempre
un registro nuevo, y el original permanece intacto (descripción de los servicios
web de la AEAT, §9.1.2 y §9.1.3). No es una factura nueva, ni una rectificativa, ni
una anulación.
POST /v1/companies/{company}/verifactu/records/{record}/subsanar- Scope:
verifactu:write - Cuerpo de la petición: ninguno — el contenido se regenera en el servidor a partir de la factura de origen y de los datos maestros actuales.
- Respuesta:
202 Acceptedcondata.id, el id del registro nuevo, que es el que se transmite. El registro nuevo empieza enpending; léelo conGET /v1/companies/{company}/verifactu/records/{id}.
El registro nuevo tiene la misma clave de factura (NIF del emisor, serie, número
y fecha) que el que corrige, su propia huella (huella) y su propia posición
en la cadena, después del último registro de la empresa: la cadena nunca se
reescribe. Siempre declara Subsanacion=S, y su RechazoPrevio depende del caso:
ninguno para un registro aceptado (§9.1.2); X para un registro rechazado cuya
factura la AEAT no tiene, porque el registro rechazado nunca existió allí (§9.1.3);
S para una subsanación rechazada de una factura que la AEAT sí tiene. No hay tope
de intentos de subsanación.
Cuándo usarla — y cuándo no
El propio registro te dice si admite subsanación: can_subsanar en el objeto registro
es true cuando el registro es un alta, está aceptado, aceptado con errores o
rechazado, es la última alta de su factura y la factura no está anulada.
| Situación | Qué hacer |
|---|---|
Registro rejected por la AEAT por un error de datos — NIF del destinatario no identificado en el censo, nombre del destinatario erróneo, problemas de descripción… | Subsanación. Corrige el dato en su origen y llama a POST …/subsanar. |
Registro rejected con aeat_error_code: SCHEMA_INVALID: no cumplía el esquema de la AEAT y nunca se envió. | Subsanación, tras corregir el dato culpable. No detiene el resto de la cadena. |
Registro accepted (o aceptado con errores) con un error de datos interno para el que las reglas de facturación no exigen una rectificativa. | Subsanación: un alta nueva sucede a la aceptada. |
Registro accepted y las reglas de facturación exigen una rectificativa (un error que debe corregirse con una factura rectificativa, una devolución, un importe distinto…). | Una factura rectificativa (R1–R5). |
Registro en error (fallo técnico: timeout, AEAT caída) o pending. | Nada — la transmisión se reintenta sola (reintento manual disponible). La subsanación responde record_not_rejected. |
| La corrección cambia un campo de la huella: NIF del emisor, serie + número, fecha de emisión, tipo de factura, cuota total o importe total. | Anulación + registro nuevo (factura nueva o rectificativa). La subsanación responde requires_annulment sin crear nada. |
El flujo
Detéctalo. Para un rechazo, suscríbete al
evento de webhook invoice.verifactu_failed, o consulta el
listado de registros
buscando status: rejected (o usa el filtro «requiere atención» de la aplicación). El
registro lleva el detalle del rechazo de la AEAT en aeat_error_code.
Corrige el dato en su origen. El registro nuevo se regenera a partir de la factura de origen y de los datos maestros actuales — por ejemplo, corrige el NIF o el nombre registrado del cliente y los valores nuevos se recogen automáticamente. El snapshot legal congelado de la factura se refresca a propósito para que el PDF coincida con lo que recibe la AEAT.
Llama al endpoint. Un registro nuevo se incorpora a la cola de transmisión de la empresa:
curl -X POST https://api.factuarea.com/v1/companies/{company}/verifactu/records/0197a2a8-4cf0-7a31-9a5e-3f2b8c1d6e42/subsanar \
-H "Authorization: Bearer fact_live_3pXnR2VbY7TcA9eFmN5z8KqW"Respuesta (202):
{
"data": {
"id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8d11",
"message": "Subsanación encolada. El registro se reenviará a la AEAT en unos segundos."
}
}data.id es el registro nuevo, nunca el que enviaste.
Observa el resultado. El registro nuevo se transmite y acaba accepted — o
rejected otra vez si los datos siguen mal, en cuyo caso vuelves a subsanar (no hay
límite de intentos).
Errores
Las violaciones de regla de negocio devuelven 422 con code: business_rule_violation
y un subcode que señala la causa:
{
"error": {
"type": "invalid_request_error",
"code": "business_rule_violation",
"subcode": "record_not_rejected",
"message": "El registro no está rechazado ni aceptado por la AEAT (estado actual: pending). Solo los registros rechazados o aceptados admiten subsanación; para fallos técnicos usa el reintento."
}
}| HTTP | code / subcode | Cuándo |
|---|---|---|
| 404 | resource_not_found | El registro no existe o pertenece a otra empresa. |
| 422 | business_rule_violation / record_not_rejected | El registro no está ni aceptado ni rechazado: está pendiente, enviado — o en error técnico, que cubre el reintento automático. |
| 422 | business_rule_violation / requires_annulment | La corrección toca campos de la huella. Anula el registro y emite una factura nueva o una rectificativa. |
| 422 | business_rule_violation / record_not_subsanable | El registro no es un alta; no es la última alta de su factura (una subsanación posterior ya la sustituye); la factura está anulada; o no tiene factura de origen desde la que regenerar. |
| 403 | insufficient_scope | La clave no tiene el scope verifactu:write. |
Evita el rechazo desde el principio
El rechazo de datos más frecuente es un destinatario que el censo de la AEAT no
identifica (rechazo 1239). Verifica el par nombre + NIF de un cliente con
POST /v1/companies/{company}/contacts/census-verification
antes de emitirle facturas VeriFactu — así la subsanación sigue siendo lo que
debe ser: una red de seguridad, no una rutina.
Un campo de datos que no cabe en el esquema de la AEAT ni siquiera llega tan lejos: la
factura no se emite (422 verifactu_not_eligible, consulta
Alta automática en VeriFactu).