How the Verifactu Hash Works
What the AEAT technical document says, explained for whoever has to program it.
Which fields go in, and in what order
The hash of an issuance record is computed over eight XML fields, in this order: IDEmisorFactura, NumSerieFactura, FechaExpedicionFactura, TipoFactura, CuotaTotal, ImporteTotal, Huella (the previous record’s hash) and FechaHoraHusoGenRegistro.
The cancellation record uses five: IDEmisorFacturaAnulada, NumSerieFacturaAnulada, FechaExpedicionFacturaAnulada, Huella and FechaHoraHusoGenRegistro. The event record, which only exists in NO VERI*FACTU mode, uses nine, starting with the computer system’s details.
How the string is built
Each field is written as name=value and joined with &. Leading and trailing spaces are stripped from the values. If a field has no value, only the name and the equals sign are written: in the system’s first record the previous hash goes as Huella=. The string is encoded in UTF-8 and hashed with SHA-256; the result is uppercase hexadecimal, 64 characters.
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
→ 3C464DAF61ACB827C65FDA19F352A4E3BDC2C640E9E9FC4CC058073F38F12F60
Why it is chained
Each record carries the previous one’s hash, so changing an old invoice breaks every later hash. That is why the chain runs per system and installation, and why two processes invoicing at the same time must serialise the calculation: if two records take the same previous hash, the chain forks.
In VERI*FACTU mode the AEAT recalculates the hash of every record it receives. If it does not match yours, the record is left “Aceptado con errores” (accepted with errors).
And the QR code
The invoice QR code contains a URL of the AEAT verification service with four parameters: nif, numserie, fecha (DD-MM-YYYY) and importe (with a decimal point). The values are URL-encoded in UTF-8: a series number such as 12345678&G33 must travel as 12345678%26G33.
The path depends on the mode: ValidarQR for VERI*FACTU and ValidarQRNoVerifactu for NO VERI*FACTU, on www2.agenciatributaria.gob.es (production) or prewww2.aeat.es (test). The optional formato=json parameter is meant for integrations, but it must never appear in the printed QR code.
We checked it on 7 October 2026 against the verification service in the AEAT test environment: the URL this tool generates with 12345678&G33 is accepted and the Agency reads the series number correctly, and an amount with a comma returns the same error 2005 that this tool flags.