VeriFactu auto-submission
There is no "send to AEAT" button. Registration is created when the invoice leaves draft — this is the list of gates that decide whether it happens, and the only manual levers that exist afterwards.
Integrators arriving from other invoicing platforms look for the operation that submits an invoice to the tax authority, do not find it, and assume the feature is missing. It is not missing: submission is not a step you perform. The registration is created as a consequence of issuing the invoice, and transmitted by a background pipeline.
This page is the answer to "why hasn't my invoice reached the AEAT?", which is almost always one of the gates below rather than a failure.
When this applies
To every invoice that leaves draft for a company whose VeriFactu activation is
effective. Concretely, the registration is created on the transition into sent
— including invoices that are born already issued: correctives, F3
substitutes, recurring generations, and creations that pass status: sent
directly.
The draft stage is deliberately outside the mechanism. A draft has no
definitive number, no frozen recipient snapshot and no fiscal existence; nothing
is declared for it.
The gates, in the order they are evaluated
Instance kill-switch. A global flag can disable VeriFactu for the whole installation. It is an emergency switch, never an activation: on its own it enables nothing.
Per-company activation. This is the one you control. It defaults to off
for a newly created account — a fresh company does not register invoices until
someone activates VeriFactu. Effective activation is instance AND company
(BR-VFC-025).
Read it with
GET /v1/verifactu/config:
the enabled field is already the effective value, not the raw company flag.
Operating mode. With activation on, a company still chooses between
transmitting and not transmitting. In no_verifactu mode the chained records are
still generated and stored locally — the mode changes transmission, not
chaining — and must be available for inspection, but nothing is sent in real
time (BR-VFC-018, RD 1007/2023 art. 16).
Historical-import bypass. Invoices loaded through the bulk import of
pre-adhesion history carry a transient flag that makes the VeriFactu handlers
return without creating any record (BR-INV-011,
BR-VFC-009). Without it, importing years of history would
declare thousands of registrations with issue dates from before the company
joined the system. The flag is forced by the importer and is not exposed on
the ordinary creation endpoints — you cannot set it from the public API.
Active certificate. Signing needs the company's own FNMT certificate. If
there is none, or it is expired, revoked, or its tax ID does not match the
company's, creation of the registration fails with a business-rule error. Check
has_active_certificate on the config endpoint before going live.
If all five pass, the record is created, chained, and queued for transmission.
Whether the queue transmits automatically is itself an instance-level setting
surfaced read-only as auto_transmit on the config endpoint.
What the API sends
Nothing you write. There is no request body for "submit", and no field on
POST /v1/invoices that
controls it. What you do control is when the invoice is issued, and everything
follows from that:
- Create the invoice as a draft, then issue it with
POST /v1/invoices/{id}/sendorPOST /v1/invoices/{id}/mark-sent. - Or create and issue atomically by passing
options.issue_directlyon the create call.
Because the "create and issue in one call" path emits both a creation and an
issue event, two handlers race to create the same registration. The command is
idempotent by invoice: the second one detects the existing registration and
silently no-ops, so exactly one record exists per invoice
(BR-VFC-008). You do not need to de-duplicate on your side.
The one explicit escape hatch
There is an operation that forces the creation of a registration for an
already-issued invoice:
POST /v1/invoices/{id}/verifactu,
scope verifactu:write. It creates the registration and enqueues its
transmission, answering 201 with the new record.
It exists for the case where an invoice was issued while a gate was closed — a certificate that had not been uploaded yet, for instance — and you want the registration once the gate opens. It is not a re-send:
| Situation | Answer |
|---|---|
| The invoice already has a registration | 422 verifactu_already_submitted |
| The invoice is still a draft, VeriFactu is disabled for the instance, or the certificate is missing, expired, revoked or has a mismatched tax ID | 422 verifactu_not_eligible |
| The invoice does not exist, or belongs to another company | 404 invoice_not_found |
curl -X POST https://api.factuarea.com/v1/invoices/0197a2a8-4cf0-7a31-9a5e-3f2b8c1d6e42/verifactu \
-H "Authorization: Bearer fact_live_3pXnR2VbY7TcA9eFmN5z8KqW"The only manual levers on a record that already exists
Once the registration exists, exactly two operations act on it, and both are covered in VeriFactu submission states:
retry— re-sends the stored declaration unchanged, for technical failures.subsanar— regenerates the declaration from corrected master data, for AEAT rejections.
There is no operation that re-transmits an accepted record. Acceptance is terminal by regulation.
Activation is a commitment, not a toggle
Turning VeriFactu on is asymmetric, and an integration that treats it as a
reversible switch will hit a 422 in production.
Moving to the verifiable mode is always allowed. Moving back is blocked until
31 December of the year in which it was activated
(BR-VFC-001, BR-VFC-023, RD 1007/2023
art. 13). The integrity of a chain declared to the AEAT in real time cannot be
downgraded to self-certified software halfway through a tax year.
There is one deliberate escape: while the chain is still empty — the company has not emitted a single billing record in any state — the company may change its mind and go back, and the lock is cleared. The first record emitted, even a rejected or errored one, arms the lock until the end of the year. Turning off the per-company activation flag is blocked by the same guard, so it cannot be used to sidestep the commitment.
GET /v1/verifactu/config exposes is_locked_until so you can show this to your
users before they commit.
Sandbox and production are not interchangeable
Each company operates against one AEAT environment, exposed as environment on
both the config object and every record. A CSV obtained against the AEAT test bed
is not a registration: test CSVs carry a recognisable prefix, and a
production database containing them means something was simulated that should
have been transmitted (BR-VFC-017).
The rule that protects you is that the system must never fall back to simulation
silently — an unreachable endpoint has to surface as a technical error state,
not as a fabricated acceptance. When you reconcile, treat the environment field
as part of the record's identity.
What appears on the PDF
Auto-submission itself adds nothing to the document; the printed artefact depends
on the existence of a record, not on how it was created. Once a record exists,
the invoice carries the legal QR block (BR-VFC-015), and the
legend under the code differs between the two operating modes: the short
VERI*FACTU mark in verifiable mode, and the full sentence stating the invoice
is verifiable at the AEAT electronic office in the other.
An invoice imported with the historical bypass has no record and therefore prints no QR. That is correct: pre-adhesion invoices are not verifiable at the AEAT.
What reaches the AEAT
One registration declaration per issued invoice, chained to the company's previous record, plus an annulment declaration if the invoice is later annulled (see Annul or correct). Nothing else is transmitted as a consequence of issuing.
In no_verifactu mode nothing reaches the AEAT in real time at all; the company
keeps the local chain for inspection and the system periodically records
summaries of its own operational events, which the regulation treats as separate
evidence (BR-VFC-018).
Traceability
Derived from the domain rules of the Factuarea backend:
BR-VFC-001— adhesion to the verifiable mode is irrevocable until the end of the calendar year, with the empty-chain exception.BR-VFC-008— idempotency: one registration per invoice, even when the create-and-issue flow fires two events.BR-VFC-009— the historical-import bypass, seen from the VeriFactu side.BR-VFC-015— the QR block and its two legends.BR-VFC-017— the sandbox/production boundary and the prohibition on silent simulation.BR-VFC-018—no_verifactumode: local chain, event summaries, no real-time transmission.BR-VFC-023— the asymmetric mode switch and the year-end lock, including the guard that stops the activation flag from bypassing it.BR-VFC-025— per-company activation, default off, effective value asinstance AND company.BR-INV-011— the historical-import bypass, seen from the invoicing side.