ADocumentation Index
Fetch the complete documentation index at: https://mintlify.com/josemmo/Verifactu-PHP/llms.txt
Use this file to discover all available pages before exploring further.
RegistrationRecord (registro de alta) is the primary billing record type in VERI*FACTU. It is used to report a newly issued invoice to the AEAT, or to resubmit and correct a previously reported one. Every registration record must contain the invoice header, an optional list of recipients, a full tax breakdown, grand totals, and a chained hash that links it to the previous record in your billing sequence.
Create the InvoiceIdentifier
Every record begins with an You can also use the constructor-less form and assign properties individually:
InvoiceIdentifier that uniquely identifies the invoice being reported. The issuer ID must be exactly 9 characters (the issuer’s NIF), the invoice number can be up to 60 characters, and the issue date must be a DateTimeImmutable.Create the RegistrationRecord and set the invoice header
Instantiate a
RegistrationRecord and assign the core header fields: the invoice identifier from the previous step, the issuer’s legal name, the invoice type, and a human-readable description of the operation.InvoiceType enum values:| Case | Value | Description |
|---|---|---|
Factura | F1 | Standard invoice (Art. 6, 7.2 and 7.3 of R.D. 1619/2012) |
Simplificada | F2 | Simplified invoice or invoice without recipient identification |
Sustitutiva | F3 | Invoice replacing previously declared simplified invoices |
R1 | R1 | Corrective invoice (Art. 80.1, 80.2 and right-based error) |
R2 | R2 | Corrective invoice (Art. 80.3) |
R3 | R3 | Corrective invoice (Art. 80.4) |
R4 | R4 | Corrective invoice (other cases) |
R5 | R5 | Corrective simplified invoice |
Add recipients
All invoice types except
Simplificada and R5 require at least one recipient. Use FiscalIdentifier for domestic entities (name + NIF) and ForeignFiscalIdentifier for foreign entities (name + ISO-3166-1 alpha-2 country code + ID type + ID value).InvoiceType::Simplificada (F2) and InvoiceType::R5 cannot have any recipients. Attempting to add recipients to these invoice types will cause validate() to fail. Up to 1000 recipients are allowed per record.Add the tax breakdown
Use
BreakdownDetails to describe each distinct tax line. You do not list individual invoice lines — only the aggregated base amount and tax amount for each unique combination of tax type, regime, and operation type.TaxType enum values:| Case | Value | Description |
|---|---|---|
IVA | 01 | Impuesto sobre el Valor Añadido |
IPSI | 02 | IPSI (Ceuta and Melilla) |
IGIC | 03 | IGIC (Canary Islands) |
Other | 05 | Other taxes |
OperationType — when to include taxRate and taxAmount:| Category | Cases | taxRate / taxAmount required? |
|---|---|---|
| Subject | Subject (S1), PassiveSubject (S2) | ✅ Yes |
| Non-subject | NonSubject (N1), NonSubjectByLocation (N2) | ❌ No |
| Exempt | ExemptByArticle20–ExemptByOther (E1–E6) | ❌ No |
A single
RegistrationRecord can contain a minimum of 1 and a maximum of 12 breakdown entries.Set the invoice totals
Set the aggregated tax total (sum of all
taxAmount values across breakdown lines) and the overall invoice total (base + tax).Chain the record to the previous one
Every record must be linked to its predecessor in the billing chain. For the very first record ever issued by your SIF, set both fields to
null. For all subsequent records, provide the InvoiceIdentifier and SHA-256 hash of the previous record.Complete working example
The snippet below puts all steps together into a single, runnable PHP file.Correction records
When a previously submitted registration record contains errors and was rejected by the AEAT, you can resubmit it as a corrected version instead of creating a brand-new record. Set$record->isCorrection = true to mark the resubmission as a correction (subsanación). Combine it with $record->isPriorRejection to describe the rejection context:
isPriorRejection value | Meaning |
|---|---|
false (default) | Not resubmitting after a rejection |
true | Resubmitting after the record was rejected in the immediately preceding submission to AEAT |
null | Resubmitting after a rejection, but the rejected record was never sent to AEAT (local-only rejection) |
isPriorRejection can only be set on records that also have isCorrection = true. Setting it without the correction flag will cause validate() to throw an InvalidModelException.