Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Eseperio/verifactu-php/llms.txt

Use this file to discover all available pages before exploring further.

VerifactuService is the central static class that orchestrates all communication with the AEAT VERI*FACTU web service. It wires together certificate management, XML serialisation, hash generation, XML signing, SOAP transport, and response parsing into the four primary operations: register, cancel, query, and QR generation. Namespace: eseperio\verifactu\services\VerifactuService
In most applications you will interact with the Verifactu facade instead of calling VerifactuService directly. The facade delegates every call to VerifactuService, but adds a more discoverable, intention-revealing API. Use VerifactuService directly when you need access to the underlying constants, want to swap configuration at runtime, or are building your own abstraction layer.

Configuration constants

These string constants are the accepted keys for the config() method and for getConfig().
ConstantValueDescription
WSDL_ENDPOINTwsdlPath or URL to the AEAT WSDL file. Defaults to the bundled SistemaFacturacion.wsdl when omitted.
SOAP_ENDPOINTsoapEndpointOverride the SOAP endpoint URL (e.g. to point at the AEAT test environment). When omitted the endpoint from the WSDL is used.
CERT_PATH_KEYcertPathAbsolute filesystem path to the PFX/P12 or PEM certificate used for SOAP authentication and XML signing.
CERT_PASSWORD_KEYcertPasswordPassword for the certificate file.
QR_VERIFICATION_URLqrValidationUrlBase URL for AEAT invoice verification, prepended to QR code payloads.

Methods

config($data): void

Sets the global configuration for the service. Call this once during application bootstrap before performing any operations.
use eseperio\verifactu\services\VerifactuService;

VerifactuService::config([
    VerifactuService::CERT_PATH_KEY     => '/var/certs/empresa.pfx',
    VerifactuService::CERT_PASSWORD_KEY => 's3cr3t',
    VerifactuService::QR_VERIFICATION_URL => 'https://sede.agenciatributaria.gob.es/Sede/verifactu/verifactu.html',
    // Optional: override SOAP endpoint for testing
    VerifactuService::SOAP_ENDPOINT => 'https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/FactuSistemaFacturacion',
]);
Accepted keys:
certPath
string
required
Absolute path to the digital certificate file (.pfx, .p12, or .pem). Must be a certificate recognised by the AEAT — typically an electronic seal or qualified certificate for the issuing entity.
certPassword
string
required
Password for the certificate. Pass an empty string '' for password-free PEM files.
qrValidationUrl
string
required
AEAT QR verification base URL. This URL is embedded in every QR code generated by generateInvoiceQr().
wsdl
string
Path or URL to the WSDL service definition. Defaults to the bundled SistemaFacturacion.wsdl included with the library. Override to use a different AEAT environment WSDL.
soapEndpoint
string
Overrides the SOAP service location URL extracted from the WSDL. Useful for targeting the AEAT pre-production (PRE) environment without providing a different WSDL.
Calling config() resets the internal SoapClient instance. Any subsequent operation will create a new client with the updated settings.

getConfig($param): mixed

Retrieves a single configuration value by key. Throws \InvalidArgumentException if the key has not been set.
$certPath = VerifactuService::getConfig(VerifactuService::CERT_PATH_KEY);

registerInvoice(InvoiceSubmission $invoice): InvoiceResponse

Registers a new invoice record with AEAT. This is the primary submission operation for VERI*FACTU. Internal execution steps:
  1. Validate the InvoiceSubmission model (all required fields, format checks). Throws \InvalidArgumentException on failure.
  2. Generate hash — calls HashGeneratorService::generate() to compute the SHA-256 huella and sets $invoice->hash.
  3. Final validation — re-validates the complete model including the newly set hash.
  4. Serialise — calls InvoiceSerializer::toInvoiceXml() to produce a RegistroAlta DOM document.
  5. Sign — calls XmlSignerService::signXml() to apply an XAdES Enveloped digital signature using the configured certificate. The signature is embedded inside the RegistroAlta element.
  6. Wrap — calls InvoiceSerializer::wrapXmlWithRegFactuStructure() to embed the signed RegistroAlta inside the RegFactuSistemaFacturacion SOAP envelope structure (Cabecera + RegistroFactura).
  7. SOAP call — invokes the RegFactuSistemaFacturacion SOAP operation via the configured SoapClient.
  8. Parse response — calls ResponseParserService::parseInvoiceResponse() on the raw SOAP response XML and returns an InvoiceResponse.
use eseperio\verifactu\models\InvoiceSubmission;
use eseperio\verifactu\models\InvoiceId;
use eseperio\verifactu\models\Chaining;
use eseperio\verifactu\models\enums\InvoiceType;
use eseperio\verifactu\services\VerifactuService;

$id = new InvoiceId('B12345678', 'FACT-2024-001', '01-01-2024');

$invoice = new InvoiceSubmission();
$invoice->setInvoiceId($id);
$invoice->issuerName  = 'Mi Empresa, S.L.';
$invoice->invoiceType = InvoiceType::STANDARD;
$invoice->taxAmount   = 21.00;
$invoice->totalAmount = 121.00;
$invoice->operationDescription = 'Servicios de consultoría';
$invoice->recordTimestamp = '2024-01-01T10:00:00+01:00';
$invoice->setChaining(new Chaining(firstRecord: 'S'));

$response = VerifactuService::registerInvoice($invoice);

if ($response->submissionStatus === 'Correcto') {
    echo 'Registered. CSV: ' . $response->csv;
}
Throws:
  • \InvalidArgumentException — model validation failed.
  • \RuntimeException — SOAP communication error or signing failure.
  • \SoapFault — AEAT service returned a SOAP fault.

cancelInvoice(InvoiceCancellation $cancellation): InvoiceResponse

Cancels a previously registered invoice record with AEAT. Internal execution steps:
  1. Validate the InvoiceCancellation model. Throws \InvalidArgumentException on failure.
  2. Generate hash — calls HashGeneratorService::generate() for the cancellation record.
  3. Final validation including hash.
  4. Serialise — calls InvoiceSerializer::toCancellationXml() to produce a RegistroAnulacion DOM document.
  5. Wrap — calls InvoiceSerializer::wrapXmlWithRegFactuStructure() to embed the record inside the SOAP structure.
  6. Sign — calls XmlSignerService::signXml() on the fully wrapped XML. The signature wraps the entire RegFactuSistemaFacturacion element for cancellations.
  7. SOAP call — invokes the RegFactuSistemaFacturacion SOAP operation.
  8. Parse response — returns an InvoiceResponse.
use eseperio\verifactu\models\InvoiceCancellation;
use eseperio\verifactu\models\InvoiceId;
use eseperio\verifactu\models\Chaining;
use eseperio\verifactu\models\enums\GeneratorType;
use eseperio\verifactu\services\VerifactuService;

$id = new InvoiceId('B12345678', 'FACT-2024-001', '01-01-2024');

$cancellation = new InvoiceCancellation();
$cancellation->setInvoiceId($id);
$cancellation->issuerName      = 'Mi Empresa, S.L.';
$cancellation->generator       = GeneratorType::ISSUER;
$cancellation->recordTimestamp = '2024-01-02T09:00:00+01:00';
$cancellation->setChaining(new Chaining(firstRecord: 'S'));

$response = VerifactuService::cancelInvoice($cancellation);

queryInvoices(InvoiceQuery $query): QueryResponse

Queries invoices previously submitted to AEAT for a given tax period.
use eseperio\verifactu\models\InvoiceQuery;
use eseperio\verifactu\services\VerifactuService;

$query = new InvoiceQuery();
$query->setIssuerparty(['name' => 'Mi Empresa, S.L.', 'nif' => 'B12345678']);
$query->year   = '2024';
$query->period = '01';

$response = VerifactuService::queryInvoices($query);

foreach ($response->foundRecords as $record) {
    echo $record['IDFactura']['NumSerieFactura'] . PHP_EOL;
}
Internal steps:
  1. Validate the InvoiceQuery model.
  2. Serialise to XML via InvoiceSerializer::toQueryXml().
  3. SOAP call — invokes ConsultaFactuSistemaFacturacion.
  4. Parse via ResponseParserService::parseQueryResponse() and return a QueryResponse.

generateInvoiceQr(InvoiceRecord $record, $destination = QrGeneratorService::DESTINATION_STRING, $size = 300, $engine = QrGeneratorService::RENDERER_GD): string

Generates an AEAT-compliant QR code for a registered invoice record. The QR encodes the verification URL with the invoice’s NIF, series number, issue date, and hash.
record
InvoiceRecord
required
An InvoiceSubmission or InvoiceCancellation whose hash field has already been set (either by registerInvoice() or manually via HashGeneratorService::generate()).
destination
string
default:"QrGeneratorService::DESTINATION_STRING"
Output destination. Use QrGeneratorService::DESTINATION_STRING to return raw image data, or QrGeneratorService::DESTINATION_FILE to save to a temp file and return its path.
size
int
default:"300"
Pixel resolution of the QR code image (width × height for PNG; viewBox size for SVG).
engine
string
default:"QrGeneratorService::RENDERER_GD"
Renderer backend. One of RENDERER_GD (PNG via GD), RENDERER_IMAGICK (PNG via ImageMagick), or RENDERER_SVG.
The base verification URL is read automatically from the qrValidationUrl configuration key.
use eseperio\verifactu\services\VerifactuService;
use eseperio\verifactu\services\QrGeneratorService;

// After registerInvoice(), $invoice->hash is populated
$pngData = VerifactuService::generateInvoiceQr(
    $invoice,
    QrGeneratorService::DESTINATION_STRING,
    300,
    QrGeneratorService::RENDERER_GD
);

// Embed in HTTP response
header('Content-Type: image/png');
echo $pngData;

Error handling

ExceptionThrown byCause
\InvalidArgumentExceptionconfig(), getConfig(), registerInvoice(), cancelInvoice(), queryInvoices()Missing or invalid configuration key; model validation failure.
\RuntimeExceptionregisterInvoice(), cancelInvoice()SOAP fault from AEAT; certificate loading failure; XML signing error.
\SoapFaultregisterInvoice(), queryInvoices()Raw SOAP-level fault from the AEAT endpoint. registerInvoice() wraps this in a \RuntimeException; queryInvoices() rethrows it.
When AEAT rejects individual invoice lines the response submissionStatus will be "AceptadoConErrores" or "Incorrecto" and the details are in $response->lineResponses[n]['CodigoErrorRegistro'] / ['DescripcionErrorRegistro']. These are not PHP exceptions — check the InvoiceResponse object after every call.

Build docs developers (and LLMs) love