Facturació des de terminals desatesos
Emet una factura simplificada ja cobrada des d'un terminal d'autoservei o una màquina expenedora en UNA sola crida idempotent, imprimeix el QR VERI*FACTU que retorna i sap què fer quan una crida falla, es repeteix o es rebutja.
Un terminal d'autoservei o una màquina expenedora venen, cobren i imprimeixen en
segons, sense ningú que corregeixi un error. Aquesta guia explica com un terminal
així fa servir POST /v1/invoices
per crear, emetre, cobrar i registrar una factura simplificada en una sola
crida, i què rep per poder imprimir-la.
L'arquitectura és la que l'AEAT admet per als terminals: un terminal més un sistema central que genera el registre de facturació i el retorna, de manera que el terminal imprimeix la factura amb el seu QR (FAQ de desenvolupadors de l'AEAT de 4 de desembre de 2025, secció 5). Factuarea és aquest sistema central. Genera, numera, encadena, signa quan el mode ho exigeix i remet tots els registres; el terminal no fa res d'això.
El programari que corre al terminal té obligacions pròpies, entre elles una declaració pròpia. Són a Compliment del component de l'integrador.
Quan aplica
A una empresa que emet factures simplificades des d'un dispositiu sense operador i té això:
- Factures simplificades habilitades per a l'empresa. Si no,
type: F2respon422simplified_invoices_disabled. - VeriFactu activat, en qualsevol dels dos modes. Comprova-ho amb
GET /v1/verifactu/config. Sense ell no es pot generar l'alta i el blocverifacturesponstatus: failedamberror_code: verifactu_not_enabled. - Una API key amb
invoices:write(iverifactu:readper seguir el registre). Comença amb una claufact_test_: els registres d'una empresa de prova mai no es remeten a l'AEAT i el seu QR apunta al servei de preproducció de l'AEAT. - Una sèrie de factures simplificades. No cal que la triïs: sense
series_idel tiquet es numera a la teva sèrie de simplificades per defecte, que es crea sola la primera vegada. Si envies unseries_id, ha de ser d'una sèrie de factures simplificades (invoice_kind: simplified); amb una sèrie de factures completes la crida respon422series_invoice_kind_mismatchi no queda cap esborrany.GET /v1/series/default?document_type=invoice&invoice_kind=simplifiedretorna la sèrie que s'usarà.
Una factura simplificada només val per a operacions de fins a 3.000 € IVA inclòs i mai per a operacions intracomunitàries, amb inversió del subjecte passiu o d'exportació. Consulta Factures simplificades o completes.
La crida
Tot va en un únic POST /v1/invoices. Aquests són els camps que el converteixen en
un cobrament desatès:
| Camp | Què fa |
|---|---|
type: "F2" | Factura simplificada. Sense client_id és un tiquet anònim; amb un, una factura simplificada qualificada. |
external_id | La identitat d'aquesta venda. No caduca mai: és el que fa segur un reintent tardà. |
prices_include_tax: true | Cada unit_price és el preu final que va pagar el client, amb IVA inclòs. |
payment | Registra el pagament (method; paid_at i reference opcionals) per tot l'import després d'emetre. |
options.register_verifactu: true | Genera l'alta VERI*FACTU abans de respondre. |
options.wait_for_pdf: true | Espera fins a uns 15 segons el PDF A4. |
options.send_automatically i options.send_to | Envia la factura per email un cop emesa. |
operation_on | El dia en què es va fer l'operació, quan difereix d'issued_on. |
curl -X POST https://api.factuarea.com/v1/invoices \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Content-Type: application/json" \
-d '{
"type": "F2",
"issued_on": "2026-06-01",
"due_on": "2026-06-01",
"external_id": "KIOSK-0042-20260601-000187",
"prices_include_tax": true,
"lines": [
{ "description": "Rentat exprés", "quantity": 1, "unit_price": 5.00, "tax_rate": 21 }
],
"payment": { "method": "credit_card", "reference": "TPV-8841-000187" },
"options": { "register_verifactu": true, "wait_for_pdf": true }
}'Per ordre, el sistema crea l'esborrany, l'emet (número definitiu), registra el pagament, genera l'alta amb la seva huella i el seu QR, envia l'email si ho vas demanar i prepara el PDF. La resposta és la factura més tres blocs:
{
"data": {
"id": "019e5b7a-3c1d-7a52-b4e1-6f2d9c8a1e37",
"type": "F2",
"number": "S-2026-001",
"status": "paid",
"subtotal": 4.13,
"total_vat": 0.87,
"total": 5,
"verifactu": {
"status": "registered",
"error_code": null,
"aeat_status": "pending",
"huella": "98F790A3765977E437FAEBCF1EF9B2B0B3462174D3D36375047185223BDE4308",
"qr_url": "https://www2.agenciatributaria.gob.es/wlpl/TIKE-CONT/ValidarQR?nif=B12345678&numserie=S-2026-001&fecha=01-06-2026&importe=5.00",
"qr_png_base64": "iVBORw0KGgo…",
"legend": "VERI*FACTU",
"csv": null
},
"pdf": {
"status": "ready",
"url": "https://app.factuarea.com/api/pdf/materialized?company=01931b3e-1111-7a2e-9a8b-3c5d6e7f8a01&expires=1780389734&type=invoice&uuid=019e5b7a-3c1d-7a52-b4e1-6f2d9c8a1e37&signature=67d5ef33797d2d164f32bd6ceedeeefd82ceed8cb2f04023db5a5e5c926fe085",
"expires_at": "2026-06-02T10:42:14+02:00"
},
"public_url": "https://app.factuarea.com/d/019e5b7a-3c1d-7a52-b4e1-6f2d9c8a1e37"
}
}(El recurs de factura porta totes les seves claus habituals; aquí només es mostren
les rellevants.) Els tres blocs apareixen només en un cobrament desatès, és a
dir, en una petició amb type: F2, un bloc payment o options.register_verifactu.
Els llistats, el detall i els webhooks mai no els porten.
verifactués el que imprimeixes.statusésregisteredquan l'alta existeix ifailedquan la factura està emesa però no s'ha pogut generar l'alta.aeat_statusés l'estat del registre davant l'AEAT: la transmissió a l'AEAT segueix el seu propi curs, per lots, després que hagis respost al client.csvésnullfins que l'AEAT l'accepta.pdfés el PDF A4.readyvol dir que està materialitzat iurlel serveix a l'instant;pendingvol dir que la generació és a la cua i la URL respon404durant uns segons. Mai no és un error.public_urlés la pàgina des de la qual el client descarrega la factura.
Preus amb IVA inclòs
Un terminal sap el que ha pagat el client, no la base neta. Amb
prices_include_tax: true cada unit_price és el preu final i Factuarea calcula
la base al cèntim perquè el total de la factura sigui igual a la suma dels
imports que has enviat. Un tiquet de 5,00 € al 21 %, per exemple, es factura amb una
base de 4,13 € més 0,87 € d'IVA, i el total és exactament els 5,00 € cobrats.
L'arrodoniment poques vegades permet un repartiment exacte: 0,60 € al 21 % no té cap base que doni 0,60 € com a línia solta. La regla és qualsevol línia, i partir:
- La línia amb la base més gran absorbeix els cèntims; si no pot, es prova cadascuna de les altres de més gran a més petita base, sense tocar mai les línies d'import zero.
- Si cap no pot, la línia més gran es parteix en dues: l'original, amb la seva quantitat, el seu descompte i els seus vincles, i una línia complementària d'una unitat amb la mateixa descripció i el mateix IVA, la base de la qual és la més petita possible (d'1 a 3 cèntims). El total continua sent exactament el que vas cobrar.
- Només es rebutja amb
422amount_reconciliation_failed, sense emetre res, una diferència més gran que un cèntim per línia, que ja no és arrodoniment. Una retenció o un recàrrec d'equivalència la poden provocar.
En aquest mode no s'admeten línies de catàleg (product_id).
IVA d'una línia. La línia pren el tax_rate que envies, després l'impost al qual
fa referència, després l'impost del seu producte i, si no n'hi ha cap, l'IVA per
defecte de l'empresa per a factures. Si l'empresa tampoc no en té, la crida
respon 422 missing_required_param amb error.param: lines.2.tax_rate i
error.line_index: 2, l'índex de la línia que cal corregir, començant per zero.
L'API mai no endevina un tipus. Els errors de domini que neixen d'una línia porten
line_index de la mateixa manera (un preu absent, una causa d'exempció fora del seu
catàleg…); és additiu, i param continua anomenant el camp.
Mostrar el QR
El QR és el QR tributari de l'AEAT: s'ha de mostrar com exigeix l'AEAT (Ordre HAC/1177/2024 i l'especificació del QR de l'AEAT). A la pràctica:
- Mida i marge. Entre 30 × 30 mm i 40 × 40 mm, amb almenys 2 mm de marge en blanc al voltant. Factuarea imprimeix 30 mm als tiquets.
- Nivell. Nivell de correcció d'errors M.
qr_png_base64ja és de nivell M i no porta prefixdata:. Si la teva impressora necessita una altra resolució, escala la imatge per un factor enter o sense interpolació perquè els mòduls es mantinguin nítids. - Rètol i llegenda. El rètol
QR tributario:va a sobre del codi i lalegendque arriba a la resposta va a sota:VERI*FACTUen mode verificable, o la frase «Factura verificable en la sede electrónica de la AEAT» en l'altre. La llegenda fa servir una lletra no més petita que la de la resta de dades de la factura. - Lloc. Al principi del document, juntament amb les dades de la factura.
- No l'alteris. Imprimeix
qr_png_base64ihuellaexactament com arriben. No els recalculis ni canviïs imports, número o data després de la resposta.
Si prefereixes no maquetar el rebut tu mateix, demana a Factuarea que te'l doni ja formatat per a un rotllo tèrmic:
curl "https://api.factuarea.com/v1/invoices/019e5b7a-3c1d-7a52-b4e1-6f2d9c8a1e37/pdf?format=ticket_80" \
-H "Authorization: Bearer fact_live_3pXnR2VbY7TcA9eFmN5z8KqW" \
--output ticket.pdfformat és a4 (el valor per defecte, amb la plantilla de l'empresa), ticket_80
(rotllo de 80 mm) o ticket_58 (rotllo de 58 mm). Un tiquet es maqueta per a una
impressora de rebuts: QR de 30 mm, sense banda de capçalera ni peu, i una alçada
ajustada al contingut. Cada format es genera i es desa a la memòria cau per
separat, així que demanar un tiquet mai no canvia l'A4 i la URL signada de l'A4
continua funcionant. El tiquet porta el contingut obligatori d'una factura
simplificada, la data de l'operació quan difereix i el destinatari quan la factura
és qualificada. L'ETag canvia quan es crea l'alta, així que un PDF descarregat
abans (sense QR) mai no es revalida com a vigent. Consulta
GET /v1/invoices/{invoice}/pdf.
Reintents, repeticions i concurrència
La xarxa perdrà la resposta d'una crida que sí que va tenir èxit. Per a això hi ha
external_id, que és independent de la capçalera Idempotency-Key: no caduca i
es desa a la factura. Consulta Idempotència.
- Reenvia la mateixa petició, amb el mateix
external_id. Si la factura ja està emesa, l'API respon200ambIdempotent-Replayed: truei aquesta factura. Abans de respondre completa el que faltava: emet un esborrany que mai no es va emetre, registra el pagament si encara hi ha saldo i genera l'alta. No crea res de nou ni consumeix un altre número. - L'email no s'envia dues vegades. Una repetició no torna a enviar per email una factura l'email de la qual ja és a la cua o lliurat.
- Una factura cancel·lada o anul·lada no rep pagament ni alta; la repetició només n'informa de l'estat.
- Una altra venda, un altre
external_id. Si el tipus o el total de la repetició difereixen de la factura emesa, la resposta és409idempotency_key_reusedambsubcode: unattended_replay_mismatchiparam: external_id. És un error en com construeixes els identificadors: no en reutilitzis mai cap. - Dues peticions simultànies amb el mateix
external_idprodueixen una factura, un número i un pagament. La segona espera fins a 20 segons la primera i després la repeteix. Si la primera no ha acabat, la segona respon409resource_lockedambparam: external_idi no ha escrit res: envia la mateixa petició una altra vegada passats uns segons.
Tria un external_id per venda que sigui estable i únic a l'empresa, com
idCaixer-data-seqüència (KIOSK-0042-20260601-000187), i desa'l abans de la
primera crida.
Quan verifactu.status és failed
La factura està emesa i numerada, però no s'ha pogut generar la seva alta.
verifactu.error_code diu per què: certificate_missing, certificate_expired,
certificate_revoked, certificate_nif_mismatch, clock_drift_exceeded,
representation_required, system_certificate_unavailable o
verifactu_not_enabled.
El terminal no ha de lliurar encara el document com a factura vàlida: tracta la
venda com a pendent, conserva el seu external_id, resol la causa (un certificat,
una representació, l'activació de VeriFactu de l'empresa) i reenvia la mateixa
petició. La repetició genera l'alta i respon 200. Consulta
Alta automàtica a VeriFactu.
Errors que el terminal ha de tractar
| Resposta | Significat | Què fer |
|---|---|---|
200 + Idempotent-Replayed: true | La venda ja estava emesa. | Imprimeix el que arriba, si el primer intent no va imprimir. |
409 idempotency_key_reused (unattended_replay_mismatch) | L'external_id pertany a un altre tipus o total. | Corregeix el generador d'identificadors. No reintentis. |
409 resource_locked | Una altra petició amb el mateix external_id continua en curs. | Envia la mateixa petició una altra vegada d'aquí a uns segons. |
422 missing_required_param, param: options.send_to | Es va demanar un email sense destinatari (sense client, o amb un client sense email). | No s'ha creat res. Envia un send_to o no demanis l'email. |
422 missing_required_param, param: lines.N.tax_rate | Una línia no té IVA i l'empresa no en té un per defecte. | Envia tax_rate o configura l'IVA per defecte. |
422 simplified_invoices_disabled / simplified_invoice_not_allowed | Les simplificades no estan habilitades, o l'import supera 3.000 € IVA inclòs. | Habilita-les a l'empresa, o emet una factura completa (F1). |
422 amount_reconciliation_failed | Els imports amb IVA inclòs no poden sumar exactament. | Revisa l'IVA, els descomptes, la retenció i el recàrrec de cada línia. |
422 verifactu_not_eligible | Alguna cosa no cap al registre de l'AEAT, o l'empresa no pot signar. | Consulta les dues taules següents. No s'emet res i no es consumeix número. |
429 i 5xx | Límit o fallada transitòria. | Reintenta amb espera creixent, amb el mateix external_id. |
422 verifactu_not_eligible: una dada no cap al registre
Abans de confirmar l'emissió, Factuarea comprova que l'alta que generarà la factura
és vàlida per a l'AEAT. Si no ho és, la factura no s'emet, no consumeix número i
te'n recuperes corregint la dada i repetint la crida. error.param la nomena, amb
el vocabulari de l'API:
error.param | Què no cap |
|---|---|
client_id | Nom del client absent o de més de 120 caràcters; un NIF espanyol que no té 9 caràcters; una identificació estrangera de més de 20; un país que l'AEAT no admet; una factura completa sense client. |
series_id | El número de la factura té més de 60 caràcters o caràcters que l'AEAT no admet (només ASCII imprimible, i ni ", ', <, > ni =). |
original_invoice_id | El número de la factura rectificada no és admissible. |
simplified_invoice_uuids | El número d'una factura simplificada substituïda per una F3 no és admissible. |
company_name | La raó social de l'empresa té més de 120 caràcters. Una raó social absent és 422 business_rule_violation, amb aquest mateix param. |
lines | Més de 12 desglossaments fiscals diferents, o una base, quota o recàrrec que no cap en 12 xifres enteres i 2 decimals. |
total | Un total, o la seva quota, que no cap al format; una F2 per sobre de 3.000 €. |
type | La marca de factura simplificada qualificada amb un tipus que no l'admet. |
422 verifactu_not_eligible: l'empresa no pot signar
Només per a una empresa que té VeriFactu activat en mode NO VERI*FACTU i no té
un certificat utilitzable. En aquest mode cada registre de facturació se signa, i un
registre només compta com a generat quan està signat, així que la factura no
s'emet ni s'anul·la. L'error porta subcode: signing_certificate_unavailable i el
motiu a error.param:
error.param | Què falta | Qui ho resol |
|---|---|---|
certificate | El certificat de l'empresa és absent, caducat, revocat, emès per a un altre NIF o il·legible. | L'empresa: Configuració → Certificat digital. |
representation | La representació que permet a Factuarea signar en nom seu no està activa (modes de remissió per tercer). | L'empresa: registrar-la, o passar al seu propi certificat. |
system_certificate | El certificat de Factuarea no està disponible. | Factuarea. Reintenta d'aquí a uns minuts; si persisteix, contacta amb suport. |
La factura queda exactament com estava (un esborrany sense número) i no es consumeix res. Una empresa amb VeriFactu desactivat, o en mode VERI*FACTU, mai no es bloqueja per aquesta regla.
Conversions, devolucions i errors
- Devolució de la mercaderia o dels diners. Una devolució és una factura
rectificativa:
POST /v1/invoices/{invoice}/corrective. La rectificativa d'una factura simplificada anònima es registra com aR5; la d'una de qualificada, com aR1aR4amb la mateixa marca. Consulta Factures rectificatives. - El client demana una factura completa de tiquets ja emesos:
POST /v1/invoices/substitute-simplifiedagrupa les factures simplificades sota unaF3. - Una operació emesa per error i ja cobrada, com un cobrament duplicat:
POST /v1/invoices/{invoice}/annulambrevert_collections: truereverteix tots els pagaments vigents i anul·la la factura en una sola operació atòmica. Si falla algun pas no es reverteix res. És una anul·lació, no un reemborsament: si el client ha de recuperar els seus diners, emet una rectificativa.can-annult'ho anticipa (requires_collection_reversal,active_collections_amount). - La conversió d'un pressupost, una proforma o un albarà en factura respon amb
warningsiwarning_codes(zero_rate_line_without_exemption) quan una línia queda al 0 % sense causa d'exempció, perquè aquests documents no la modelen. No bloqueja: la factura és un esborrany i fixes la causa abans d'emetre-la.
Sense connexió no hi ha factura
No hi ha cap mode sense connexió. Un terminal sense connexió no emet: la factura existeix només quan l'API ha respost, perquè el seu registre de facturació s'ha de generar de manera simultània o immediatament anterior a la seva emissió (RD 1007/2023, art. 9). El terminal no ha d'imprimir un document com a factura amb una numeració pròpia per enviar-la després. Què fer amb una venda que no es pot facturar en aquell moment és una decisió de l'operador, aliena a Factuarea.
Compliment del component de l'integrador
El que ha de fer i declarar el programari del teu terminal.
Idempotència
Idempotency-Key i l'external_id durador.
Alta automàtica a VeriFactu
Lots, reintents i les palanques sobre un registre.
Factures simplificades o completes
F1, F2 i F3 i la factura simplificada qualificada.