Veri*Factu
When you issue a sales invoice, Bilteo generates its Veri*Factu billing record, chains it to the previous record using a hash and submits it to the AEAT. This is automatic: you do not need to build or sign anything.
What Bilteo generates
- A registration record (
RegistroAlta) when a sales invoice is issued. - A cancellation record (
RegistroAnulacion) when an issued invoice is cancelled. - Each record includes a SHA-256 hash calculated from its key fields and the hash of the tenant's previous record, forming a tamper-evident chain.
Invoice A (registration) ──hash──▶ Invoice B (registration) ──hash──▶ Invoice A (cancellation) ─▶ …
└── chained per tenant: each record references the previous record's hashSubmission and record statuses
Generation and submission are decoupled: the record starts as pending and a later process submits it to the AEAT. Its status reflects the response:
| Status | Meaning |
|---|---|
pending | Generated and waiting to be sent. |
in-process | Sent and awaiting a response. |
accepted | Accepted by the AEAT. |
accepted_error | Accepted with errors (registered). |
rejected | Rejected (not registered with the AEAT). |
unknown_response | No final response: transport error or unparseable reply. response_code carries the cause (SOAP_CLIENT, HTTP_<status>, INVALID_JSON, INVALID_TYPE). Not a fiscal rejection; needs review. |
Transient network or AEAT errors do not change the status: the record goes back to pending and is retried automatically.
A record with a final response (rejected, accepted or accepted_error) can be corrected.
Do not poll: use webhooks
Instead of repeatedly checking the status, subscribe to verifactu.accepted / verifactu.rejected and Bilteo will notify you when the AEAT responds.
QR code
Every issued invoice includes its AEAT verification QR code (tax ID, series number, date and total amount), which the recipient can use to verify it. Bilteo embeds it when rendering the PDF.
Reading records
With the verifactu:read scope you can retrieve records and their status through the API. See the Reference.
In testing
In a test tenant, records are submitted to the AEAT certification environment, never production. You can also disable record generation when you only need to test your integration. See the Test environment.