LiveES

VeriFactu compliance records (ES)

Two endpoints, one question: how do you show the AEAT that your invoicing follows the Spanish rules? One hands out the software's declaración responsable, the other the complete registro chain of one NIF.

GET/api/v1/verifactu/declaracion
GET/api/v1/verifactu/chain/{vatId}/export

Why these two endpoints exist

Real Decreto 1007/2023 requires two things an inspector must be able to see: the software manufacturer's declaration of responsibility (art. 13.2, elaborated in art. 15 Orden HAC/1177/2024) and the records themselves (art. 14). The regulation says they must be viewable inside the system — for an API product that means retrievable over the API. That is exactly what these two calls do.

The declaración responsable

Art. 13.2

Hands out the declaration of responsibility for this invoicing system as plain text plus metadata. It describes the manufacturer of the software — us — not your organisation, and is therefore identical for every API key.

bash
1curl https://service.invoice-api.xhub.io/api/v1/verifactu/declaracion \
2 -H "Authorization: Bearer sk_live_abc123..."

Watch hasPendingLegalReview. While it is true the wording still carries our internal legal-review marker: the document is then a draft, not a signed declaration. For a submission to the AEAT, wait until it reads false.

Response of the declaración

200 OK
json
1{
2 "text": "DECLARACIÓN RESPONSABLE\n\nEl productor del sistema informático de facturación ...",
3 "version": "1.5.0",
4 "hasPendingLegalReview": false,
5 "producedAt": "2026-09-28T09:14:22.318Z"
6}
FieldTypeDescription
textstringThe declaración responsable in full, as plain text (Spanish, art. 13.2).
versionstringSoftware version the declaration was signed for — the version from IdSistemaInformatico.
hasPendingLegalReviewbooleantrue while the wording still carries our internal legal-review marker. The document is then a draft.
producedAtstring (ISO-8601)ISO-8601 timestamp of this rendering.

The registro chain export

Art. 14

Hands out every registro of one NIF's chain as ONE json document, ordered by sequence number. Each entry carries the frozen registro next to its huella — exactly the object the hash was computed over, passed through unchanged and never reshaped. The recipient can recompute the hash from it.

The export is scoped to the organisation behind the API key. A chain owned by someone else is not visible and comes back as an empty export — not as an error.

Above 5,000 entries a range is mandatory: from, to or both. Without it the API answers 400 and names the entry count. Both values are ISO-8601 and narrow by the entry's timestamp.

Query parameters

FieldTypeRequiredDescription
fromstring (ISO-8601)-Only entries appended at or after this ISO-8601 instant. Mandatory — alone or together with to — once the chain exceeds the export limit.
tostring (ISO-8601)-Only entries appended at or before this ISO-8601 instant.

Example

bash
1# The whole chain of one NIF
2curl "https://service.invoice-api.xhub.io/api/v1/verifactu/chain/B12345678/export" \
3 -H "Authorization: Bearer sk_live_abc123..."
4 
5# Narrowed to a range — mandatory above 5000 entries
6curl "https://service.invoice-api.xhub.io/api/v1/verifactu/chain/B12345678/export?from=2026-01-01T00:00:00Z&to=2026-03-31T23:59:59Z" \
7 -H "Authorization: Bearer sk_live_abc123..."

Response of the chain export

200 OK
json
1{
2 "vatId": "B12345678",
3 "exportedAt": "2026-09-28T09:20:04.771Z",
4 "from": "2026-01-01T00:00:00.000Z",
5 "to": "2026-03-31T23:59:59.000Z",
6 "entryCount": 2,
7 "entries": [
8 {
9 "sequenceNumber": 1,
10 "invoiceId": "inv_01J8Z3K9QW",
11 "invoiceNumber": "A/2026-0001",
12 "huella": "3C1F9A72B84E05D6C7A1938E4F20B5D8A6C3E71F9B2D48065A1C7E39F2B8D4E60",
13 "previousHuella": "",
14 "recordType": "ALTA",
15 "createdAt": "2026-01-03T08:41:12.004Z",
16 "registro": {
17 "IDFactura": {
18 "IDEmisorFactura": "B12345678",
19 "NumSerieFactura": "A/2026-0001",
20 "FechaExpedicionFactura": "03-01-2026"
21 },
22 "ImporteTotal": "1785.00"
23 },
24 "status": "ACCEPTED",
25 "resultCsv": "AAAgOKbwQ8iQ7wAAAAA",
26 "lastError": null
27 },
28 {
29 "sequenceNumber": 2,
30 "invoiceId": "inv_01J8Z4M2RT",
31 "invoiceNumber": "A/2026-0002",
32 "huella": "B7E2D46901C8A35F7E1B9D24608C5A3F1E7B9D2460C8A5F3E1B7D9460C2A8F5E3",
33 "previousHuella": "3C1F9A72B84E05D6C7A1938E4F20B5D8A6C3E71F9B2D48065A1C7E39F2B8D4E60",
34 "recordType": "ALTA",
35 "createdAt": "2026-01-04T10:02:55.612Z",
36 "registro": {
37 "IDFactura": {
38 "IDEmisorFactura": "B12345678",
39 "NumSerieFactura": "A/2026-0002",
40 "FechaExpedicionFactura": "04-01-2026"
41 },
42 "ImporteTotal": "952.00"
43 },
44 "status": "PENDING",
45 "resultCsv": null,
46 "lastError": null
47 }
48 ]
49}
FieldTypeDescription
vatIdstringThe NIF this chain belongs to — the chain key.
exportedAtstring (ISO-8601)ISO-8601 timestamp of THIS export, not of the last entry.
fromstring | nullLower bound of the exported range, or null.
tostring | nullUpper bound of the exported range, or null.
entryCountintegerNumber of entries in entries.
entriesarrayThe entries, ordered by sequence number — shape below.

One entry of the chain

FieldTypeDescription
sequenceNumberintegerPosition in the chain, 1-based and gapless.
invoiceIdstringInternal id of the invoice this entry belongs to.
invoiceNumberstring | nullInvoice number as issued, or null if the entry predates numbering.
huellastringThe entry hash (huella) as stored — recomputable from registro.
previousHuellastringHuella of the preceding entry; an empty string for the first entry of the chain.
recordTypestring | nullALTA for an issuance or ANULACION for a cancellation, as recorded.
createdAtstring (ISO-8601)ISO-8601 timestamp the entry was appended to the chain.
registroobjectThe frozen registro exactly as it went to the AEAT — the object the huella was computed over. Not reshaped.
statusstring | nullSubmission state of the matching queue row, such as ACCEPTED or PENDING, or null.
resultCsvstring | nullThe AEAT CSV once the registro was accepted.
lastErrorstring | nullLast submission error for this entry, verbatim.

Errors

StatusCodeDescription
400Bad RequestEither from or to is not a valid ISO-8601 date, or the chain is too large to export without a range — the message names the entry count.
401UNAUTHORIZEDAPI key missing or invalid, or the key has no organisation.
502CONFIG_MISSINGThe platform is missing mandatory VERIFACTU configuration. The message names every missing variable.