La huella SHA-256 encadenada, campo a campo
Los ocho campos, su orden exacto, los tres formatos que hay que clavar y los ejemplos oficiales de la AEAT resueltos. Es la parte del reglamento que no se puede corregir después.
¿Cómo se calcula la huella de un registro VeriFactu?
Se concatenan ocho campos del registro como «Campo=valor» unidos por «&», en el orden que fija la AEAT, y se aplica SHA-256, expresando el resultado en hexadecimal mayúscula.
Los ocho campos del registro de alta son IDEmisorFactura, NumSerieFactura, FechaExpedicionFactura, TipoFactura, CuotaTotal, ImporteTotal, Huella (la del registro anterior) y FechaHoraHusoGenRegistro. La fecha va en dd-mm-aaaa, los importes con dos decimales y punto, y la marca de tiempo en ISO-8601 con huso horario.
Fuente: Orden HAC/1177/2024, de 17 de octubre · Real Decreto 1007/2023, de 5 de diciembre
La huella de un registro de alta se calcula sobre ocho campos, en un
orden fijo, escritos como Campo=valor y unidos por &.
Ni un espacio de más, ni un campo fuera de sitio.
| Campo | Formato |
|---|---|
IDEmisorFactura | NIF del emisor, sin espacios. |
NumSerieFactura | Serie y número en un mismo campo, tal cual, hasta 60 caracteres. Series y numeración. |
FechaExpedicionFactura | dd-mm-aaaa. No el ISO. |
TipoFactura | F1, F2, F3 o R1 a R5. |
CuotaTotal | Dos decimales, punto, sin separador de miles. |
ImporteTotal | Igual que la cuota. |
Huella | La del registro anterior del mismo emisor. Vacía en el primero. |
FechaHoraHusoGenRegistro | ISO-8601 con huso horario. |
# Los ocho campos, en ESTE orden, unidos por & IDEmisorFactura=89890001K&NumSerieFactura=12345678/G33&FechaExpedicionFactura=01-01-2024&TipoFactura=F1&CuotaTotal=12.35&ImporteTotal=123.45&Huella=&FechaHoraHusoGenRegistro=2024-01-01T19:20:30+01:00 # SHA-256, hexadecimal en MAYÚSCULAS: 3C464DAF61ACB827C65FDA19F352A4E3BDC2C640E9E9FC4CC058073F38F12F60
«12» y «12.00» son la misma cantidad y dos huellas distintas.
// Importe: punto decimal, sin miles, SIEMPRE dos decimales number_format($valor, 2, '.', ''); // 12 → "12.00" ← NO "12" // 12.3 → "12.30" ← el cero final se conserva // 1234567.89 → "1234567.89" ← sin separador de miles // Fecha: dd-mm-aaaa, NO el ISO aaaa-mm-dd date('d-m-Y', $t); // 2026-08-26 → "26-08-2026" // Marca de tiempo: ISO-8601 CON huso horario (new DateTimeImmutable($cuando, $tz))->format('c'); // "2026-08-26T10:15:00+02:00" ← sin el huso, no cuadra
# La anulación lleva OTROS campos y en OTRO orden. # Los tres primeros con sufijo «Anulada», sin tipo ni importes. IDEmisorFacturaAnulada=89890001K&NumSerieFacturaAnulada=12345679/G34&FechaExpedicionFacturaAnulada=01-01-2024&Huella=F7B94CFD8924EDFF273501B01EE5153E4CE8F259766F88CF6ACB8935802A2B97&FechaHoraHusoGenRegistro=2024-01-01T19:20:40+01:00 # SHA-256: 177547C0D57AC74748561D054A9CEC14B4C4EA23D1BEFD6F2E69E3A388F90C68
Cada huella entra en la siguiente
El campo Huella de un registro es la huella del registro anterior del mismo emisor. Eso convierte la secuencia en una cadena: alterar un registro pasado invalidaría todos los posteriores.
Un defecto de formato se arrastra
Si el primer registro se calculó con un formato equivocado, su huella es la que entra en el segundo, que entra en el tercero. No se arregla recalculando: habría que rehacer el histórico entero, y el histórico ya está remitido.
La concurrencia bifurca la cadena
Dos procesos que registren a la vez para el mismo emisor pueden leer el mismo «anterior» y encadenarse los dos a él. La AEAT los acepta. Hay que serializar por emisor, y esa es la razón de que la remisión sea asíncrona.
Por eso no te dejamos calcular la huella
La huella depende de un estado —el último registro de ese emisor— que vive en el motor. Si la calculas tú y nos la mandas, la bifurcación deja de ser evitable.
¿Qué es la huella en VeriFactu?
El SHA-256, en hexadecimal mayúscula, de una cadena formada por ocho campos concretos del registro de facturación en un orden fijo, incluida la huella del registro anterior. Ese encadenamiento es lo que permite detectar si un registro pasado se ha alterado.
¿Qué huella lleva la primera factura?
El campo Huella va vacío. En la cadena aparece literalmente «Huella=&» — el campo existe, con valor vacío. Omitirlo daría una cadena distinta y por tanto otra huella.
¿La huella cambia según la modalidad de remisión?
No. Los campos que entran en la huella son los mismos remitas tú o remita tu cliente, así que un emisor puede cambiar de modalidad sin romper su cadena ni invalidar lo ya remitido.
¿Se puede recalcular una huella mal calculada?
No de forma útil. Podrías recalcularla, pero ya has remitido registros posteriores encadenados a la incorrecta. Rehacer el histórico implica reenviar todo, y lo remitido ya está en la AEAT.
¿Contra qué se puede verificar mi implementación?
Contra los tres ejemplos resueltos que la AEAT publica en sus especificaciones de huella. Si tu motor reproduce los tres byte a byte, el formato es correcto. Los tres están en esta página.
Última revisión normativa: Especificaciones de huella AEAT v0.1.2 Revisado por el equipo técnico de verifactu.co