Unattended checkout invoicing
A paid simplified invoice from a kiosk in one idempotent call, VeriFactu remission through Factuarea, subsanación of accepted records and per-line errors. Three breaking changes: a line without a rate no longer takes 21 %, issuing is rejected when the record does not fit the AEAT schema, and in NO VERI*FACTU mode it needs a usable certificate. POST /v1/verifactu/records/{id}/retry no longer answers max_retries_exceeded.
3 October 2026 — A self-service terminal or a vending machine can now issue a paid simplified invoice, with its VERI*FACTU QR, in one idempotent call. Behind it there is a rework of how the records reach the AEAT, a way to remit through Factuarea instead of with your own certificate, and a stricter check before an invoice is issued. Read the three breaking changes first; the new and the updated operations are listed at the end.
Breaking changes
1. A line with no VAT rate no longer takes 21 %. A sales line with no
tax_rate, no referenced tax and no product with a tax now takes the default
VAT of the company for that kind of document. If the company has none, the call
answers 422 missing_required_param with error.param: lines.N.tax_rate. It
applies to invoices, quotes, proformas, delivery notes and recurring invoices, in
the API v1 and in MCP. Send tax_rate explicitly, or set the default VAT.
2. An invoice whose record does not fit the AEAT is not issued. With VeriFactu
enabled, an invoice that used to be issued and whose record failed afterwards now
answers 422 verifactu_not_eligible before it is issued, with the field in
error.param. No number is consumed. The limits are in the
table below.
3. NO VERI*FACTU mode needs a usable certificate to issue and to annul. A
company that has enabled VeriFactu in NO VERI*FACTU mode and has no usable
certificate can no longer issue or annul until it uploads one: the operation
answers 422 verifactu_not_eligible with subcode: signing_certificate_unavailable
and error.param certificate, representation or system_certificate, and the
invoice stays as it was. It does not affect companies with VeriFactu disabled
— whose default mode is no_verifactu without being in the system — nor
companies in VERI*FACTU mode, which are never blocked by it.
Also, POST /v1/verifactu/records/{record}/retry no longer answers
max_retries_exceeded for billing records: there is no limit of attempts any
more. The code still applies to the retry of an event in no_verifactu mode.
Unattended checkout in POST /v1/invoices
POST /v1/invoices and the
MCP tool create_invoice gain, with the same semantics:
type: "F2": a simplified invoice, with no client (anonymous ticket) or with one (qualified simplified invoice, registered asF1withFacturaSimplificadaArt7273).prices_include_tax: theunit_priceof every line is the final price, and the base is computed to the cent so the total equals the sum you sent ("any line, and split";422amount_reconciliation_failedonly when a withholding or a surcharge moves the total).payment(method,paid_at,reference): the payment is registered after issuing.operation_on: the day of the operation when it differs fromissued_on.options.register_verifactu: the VeriFactu alta is generated before responding.options.wait_for_pdfwaits up to about 15 seconds for the A4 PDF.
The 201 carries three extra blocks, only for a checkout: verifactu (status,
error_code, aeat_status, huella, qr_url, qr_png_base64, legend, csv),
pdf (status, url, expires_at) and public_url. The guide is
Unattended checkout invoicing, and what your terminal
must declare is in
Compliance of the integrator's component.
Resending by external_id never expires:
- The same
external_idwith the same type and total answers200withIdempotent-Replayed: trueand the invoice already issued, completing the alta and the payment if they were missing. A queued or delivered email is not sent again. - A different type or total answers
409idempotency_key_reused, witherror.type: idempotency_error,subcode: unattended_replay_mismatchandparam: external_id. - Another request with the same
external_idstill running makes the second one wait up to 20 seconds, and then answer409resource_lockedif the first has not finished; the same request can be sent again.
An email requested with no possible recipient (options.send_automatically without
options.send_to and with no client email) is rejected before anything is
created: 422 missing_required_param with error.param: options.send_to, no draft
and no number. It also applies to the other POST /v1/invoices requests, which used
to reject after creating the draft.
Issuing is rejected when the record does not fit
422 verifactu_not_eligible is returned by the operations that issue an invoice:
POST /v1/invoices with options, POST /v1/invoices/{id}/issue,
POST /v1/invoices/{id}/send and …/mark-sent when they issue,
POST /v1/invoices/{id}/corrective and POST /v1/invoices/substitute-simplified.
The invoice stays a draft and consumes no number; you fix the field and repeat. In
bulk-create and bulk-status the rejection appears in failures[], per element.
error.param | Cause |
|---|---|
client_id | Client name missing or longer than 120 characters; a Spanish tax ID that is not 9 characters; a foreign identification longer than 20; a country the AEAT does not accept; a complete invoice with no client. |
series_id | The invoice number has more than 60 characters or characters the AEAT does not accept. |
original_invoice_id | The number of the corrected invoice is not admissible. |
simplified_invoice_uuids | The number of a substituted simplified invoice is not admissible. |
company_name | Company name longer than 120 characters. A missing company name is 422 business_rule_violation with the same param. |
lines | More than 12 tax breakdowns, or an amount that does not fit 12 integer digits and 2 decimals. |
total | A total, or its tax, that does not fit the format; an F2 above 3.000 €. |
type | The qualified-simplified mark with a type that does not admit it. |
No usable signing certificate
For a company with VeriFactu enabled in NO VERI*FACTU mode, issuing and
annulling are rejected before they run when the company cannot sign the record. The
operations are POST /v1/invoices with options, …/issue, …/send, …/mark-sent,
…/corrective, substitute-simplified, …/annul and …/void. error.param says
what is missing:
error.param | What is missing | Who fixes it |
|---|---|---|
certificate | The company certificate is missing, expired, revoked, for another tax ID or unreadable. | The company, in Settings → Digital certificate. |
representation | The representation that lets Factuarea sign on the company's behalf is not active. | The company: register it or change to its own certificate. |
system_certificate | The certificate of Factuarea is unavailable. | Factuarea. |
GET /v1/invoices/{invoice}/can-annul anticipates it: can_annul is false and
reasons carries the same message. In bulk-status the rejection appears in
failures[], per element. See
VeriFactu auto-submission.
Annulling a paid operation, tickets and the date of the operation
revert_collections—POST /v1/invoices/{invoice}/annulaccepts it (falseby default). Withtrue, every live payment is reverted with the reserved reasonissued_in_errorand the invoice is annulled in one atomic operation.GET …/can-annuladdsrequires_collection_reversalandactive_collections_amount.POST /v1/invoices/{invoice}/payments/{payment}/reversalrejectsissued_in_errorwith422reversal_reason_reserved.POST …/voidhas no such option.- Ticket format —
GET /v1/invoices/{invoice}/pdfand…/pdf-linkacceptformat:a4(default),ticket_80orticket_58. Each format is rendered and cached separately, and theETagchanges when the VeriFactu alta is created and with the format. operation_on— the invoice resource returns it, andPOST /v1/invoices,PUT /v1/invoices/{invoice}andPOST /v1/invoices/bulk-createaccept it. It cannot be later thanissued_on(422operation_date_after_issue_date) unless the first line that declares aregime_keyuses 14 or 15, and a corrective invoice inherits it.- Payment detail — every entry of
payments.detailin the invoice resource carries the five reversal keys (is_reversed,reversed_at,reversal_reason,reversal_reason_textandreversal_note), also for a payment still in force (falseandnull). - Proforma shipping —
shipping_costis an amount with VAT included. Converting the proforma to an invoice breaks it down into base and VAT and keeps the total. - Conversions — converting a quote, a proforma or a delivery note answers, only when
there is something to warn about,
warningsandwarning_codes(zero_rate_line_without_exemption): a line stayed at 0 % with no exemption cause. It does not block. Thewarningsof the corrective invoice is now optional.
Errors that name the line
A domain error that comes from one line of a document carries line_index, the
zero-based position of the line, next to param: error.line_index in the API (and
as a root member of application/problem+json) and error.data.line_index in MCP. It
is additive; param keeps naming the field exactly as before.
Corrective invoices and editing
- Per-line nature in a corrective —
POST /v1/invoices/{invoice}/correctiveand the toolcreate_corrective_invoiceacceptunit,regime_key,exemption_reasonandexemption_reason_textper line. A key you omit inherits the original line by index; a key you send replaces it;nullmeans none. - Edits do not revalidate what was already saved. Editing a document of the five
sales families no longer demands that the references already stored on it (catalog
variant or presentation, configuration, options, linked expenses) are still active
or existing. Changed or new references are validated as always.
update_delivery_notein MCP validates like the API. original_pack_datais returned and kept in the lines of proformas and delivery notes too, so it survives edits and the conversion to an invoice.
VeriFactu: remission, blocked records and subsanación
- Remission by batches — the records of a company go to the AEAT in ordered batches of up to 1.000, respecting the waiting time the AEAT states, with the answer read record by record. Technical failures retry at least every hour with no cap. See How the records reach the AEAT.
POST /v1/verifactu/records/retry-blocked(new, scopeverifactu:write) — reactivates every blocked record of the company and answers202withdata.reactivated. The MCP tool isretry_blocked_verifactu_records.- Statistics —
GET /v1/verifactu/statsaddspending_incident_count,blocked_incident_countandoldest_pending_at. - Record — adds
is_blocked,block_reason,aeat_error_code(it includesSCHEMA_INVALID, a record that broke the AEAT schema and was never sent) andcan_subsanar. POST /v1/verifactu/records/{record}/subsanar— it now also admits accepted records and always generates a new record:data.idis the id of the new one, not of the record you sent. Subsanación errors arerecord_not_rejected,record_not_subsanableandrequires_annulment. See VeriFactu record subsanación.- Remission by a third party —
GET,POSTandDELETE /v1/verifactu/representation(new) register, read and revoke the representation, withvalid_until(at most five years),is_expiredand a warning 30 and 7 days before it expires, andremission_modeinPUT /v1/verifactu/settings. The201of the registration carriesremission_mode; revoking takesreasonof 3 to 500 characters.GET /v1/verifactu/configaddsremission_mode,social_collaborator_available,has_active_representation,active_representation_valid_until,active_representation_is_expiredandpresenter_certificate_status. The MCP tools areget_company_representation,register_company_representationandrevoke_company_representation. - Declaración responsable —
GET /v1/verifactu/declaracion-responsablereturns the content of article 15:components,producer_addressandsignature_types, andsystem_nameis now the name of the system and not its code. - Simplified invoices — a simplified invoice with the recipient's tax ID is
registered as
F1withFacturaSimplificadaArt7273, and its corrective asR1toR4; the corrective of an anonymous one staysR5.
Error codes: verifactu_not_eligible,
signing_certificate_unavailable,
resource_locked,
idempotency_key_reused,
unattended_replay_mismatch,
amount_reconciliation_failed,
reversal_reason_reserved,
operation_date_after_issue_date,
simplified_invoices_disabled,
representation_required,
invalid_representation and
social_collaborator_unavailable.
Migration
- Send
tax_rateon every sales line, or set the default VAT of the company for each kind of document, and handle422missing_required_paramwithlines.N.tax_rate. - Handle
422verifactu_not_eligibleon every operation that issues an invoice: it is recoverable by fixing the field inerror.param. - If a company runs VeriFactu in NO VERI*FACTU mode, check it has a usable certificate (or an active representation) before issuing or annulling.
- Stop branching on
max_retries_exceededfor billing records. - If you call
subsanar, readdata.idas the new record. - A terminal sends a stable
external_idper sale and resends the same request until it gets a definitive answer.
New endpoints4
| Endpoint | Description |
|---|---|
POST/v1/verifactu/records/retry-blocked | Retry every blocked VeriFactu record |
GET/v1/verifactu/representation | Retrieve the active representation |
POST/v1/verifactu/representation | Register a representation |
DEL/v1/verifactu/representation | Revoke the active representation |