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.

The following services form the internal infrastructure of the library. Under normal usage they are called automatically by VerifactuService — you rarely need to interact with them directly. Each section notes whether direct use is recommended.

CertificateManagerService

Namespace: eseperio\verifactu\services\CertificateManagerService Handles loading, parsing, and validating the digital certificate (.pfx, .p12, or .pem) used for XML signing and SOAP mutual-TLS authentication. Supports both PHP’s built-in openssl_pkcs12_read() and an automatic CLI fallback (openssl pkcs12 -legacy) for older PKCS#12 bundles encrypted with RC2-40. Direct use: Optional. Most applications let VerifactuService manage certificates automatically. Call these methods directly when you want to pre-validate a certificate at deployment time.

getCertificate($certPath, $certPassword = ''): string|false

Extracts and returns the X.509 certificate block in PEM format (-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----).
use eseperio\verifactu\services\CertificateManagerService;

$pem = CertificateManagerService::getCertificate('/var/certs/empresa.pfx', 's3cr3t');
Throws: \RuntimeException if the file is not found, the password is wrong, or the format is unsupported.

getPrivateKey($certPath, $certPassword = ''): string|null

Extracts and returns the private key in PEM format. Returns null if the private key could not be extracted from a PFX/P12 bundle.
$key = CertificateManagerService::getPrivateKey('/var/certs/empresa.pfx', 's3cr3t');

isValid($certPath, $certPassword = ''): bool

Returns true if the certificate is currently within its validity window (validFrom ≤ now ≤ validTo).
if (!CertificateManagerService::isValid('/var/certs/empresa.pfx', 's3cr3t')) {
    throw new \RuntimeException('Certificate is expired. Renew before submitting invoices.');
}

createSoapCompatiblePemTemp(string $certPath, string $certPassword = ''): string

Combines the certificate and private key into a single PEM file in the system temp directory, sets permissions to 0600, and registers a PHP shutdown function to delete it. Returns the absolute path to the temporary file. This is the method called internally by VerifactuService before creating the SoapClient — PHP’s SoapClient requires a combined PEM file when using mutual TLS.
$tmpPemPath = CertificateManagerService::createSoapCompatiblePemTemp(
    '/var/certs/empresa.pfx',
    's3cr3t'
);
// Pass $tmpPemPath to SoapClientFactoryService::createSoapClient()
Throws: \RuntimeException if the temp file cannot be written.

SoapClientFactoryService

Namespace: eseperio\verifactu\services\SoapClientFactoryService Creates and configures a PHP \SoapClient instance for communicating with the AEAT VERI*FACTU endpoints. Configures mutual TLS using the combined PEM produced by CertificateManagerService::createSoapCompatiblePemTemp(). Direct use: Rarely needed. VerifactuService creates the client lazily on first operation and caches it. Use directly when building a custom SOAP pipeline.

createSoapClient(string $wsdl, string $certPath, string $certPassword, array $options = []): \SoapClient

wsdl
string
required
Path or URL to the AEAT WSDL file. Local file paths are automatically prefixed with file:// so that libxml can resolve relative imports within the WSDL.
certPath
string
required
Path to the combined PEM file produced by createSoapCompatiblePemTemp(). This is set as local_cert in the SoapClient options.
certPassword
string
Certificate passphrase (set as passphrase in SoapClient options). Pass '' for unprotected PEM files.
options
array
Additional SoapClient constructor options that override or extend the defaults. Use ['location' => '<url>'] to override the SOAP endpoint (e.g. for the AEAT pre-production environment).
Default SoapClient options applied:
OptionValue
trace1 (enables __getLastRequest() / __getLastResponse())
exceptionstrue
local_cert$certPath
passphrase$certPassword
cache_wsdlWSDL_CACHE_NONE
use eseperio\verifactu\services\CertificateManagerService;
use eseperio\verifactu\services\SoapClientFactoryService;

$pemPath = CertificateManagerService::createSoapCompatiblePemTemp('/var/certs/empresa.pfx', 's3cr3t');

$client = SoapClientFactoryService::createSoapClient(
    '/path/to/SistemaFacturacion.wsdl',
    $pemPath,
    's3cr3t',
    ['location' => 'https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/FactuSistemaFacturacion']
);
Throws: \RuntimeException if the certificate file is not found or SoapClient construction fails.

ResponseParserService

Namespace: eseperio\verifactu\services\ResponseParserService Parses the raw SOAP XML response returned by the AEAT web service into strongly-typed PHP model objects. Uses DOMDocument and DOMXPath with local-name() queries to avoid namespace binding issues. Direct use: Unlikely. VerifactuService always calls the appropriate parse method after each SOAP operation.

parseInvoiceResponse($xmlResponse): InvoiceResponse

Parses the response to a RegFactuSistemaFacturacion call (both registration and cancellation) and returns an InvoiceResponse.
use eseperio\verifactu\services\ResponseParserService;

$response = ResponseParserService::parseInvoiceResponse($rawSoapXml);

echo $response->submissionStatus; // "Correcto" | "AceptadoConErrores" | "Incorrecto"
echo $response->csv;              // Secure verification code (when present)
echo $response->waitTime;         // Seconds to wait before next submission batch

foreach ($response->lineResponses as $line) {
    echo $line['EstadoRegistro'];           // "Correcto" | "Incorrecto" | "AceptadoConErrores"
    echo $line['CodigoErrorRegistro'];      // AEAT error code (e.g. "1105")
    echo $line['DescripcionErrorRegistro']; // AEAT error description
    echo $line['ErrorDescription'];         // Human-readable message from ErrorRegistry
}
InvoiceResponse properties:
PropertyTypeDescription
csvstring|nullSecure verification code (Código Seguro de Verificación).
headerarray|nullParsed Cabecera block as an associative array.
waitTimestring|nullTiempoEsperaEnvio — throttling wait time in seconds.
submissionStatusstring|nullEstadoEnvio — overall status of the submission batch.
submissionDataarray|nullDatosPresentacion block as an associative array.
lineResponsesarrayArray of per-invoice line response objects (see above).
Throws: \RuntimeException if the XML response cannot be parsed.

parseQueryResponse($xmlResponse): QueryResponse

Parses the response to a ConsultaFactuSistemaFacturacion call and returns a QueryResponse.
$response = ResponseParserService::parseQueryResponse($rawSoapXml);

echo $response->queryResult;         // "ConDatos" | "SinDatos"
echo $response->paginationIndicator; // "S" if more pages exist

foreach ($response->foundRecords as $record) {
    // Each record is an associative array mirroring RegistroRespuestaConsultaFactuSistemaFacturacion
    echo $record['IDFactura']['NumSerieFactura'];
}
QueryResponse properties:
PropertyTypeDescription
headerarray|nullParsed Cabecera block.
periodarray|nullPeriodoImputacion block (year and period).
paginationIndicatorstring|nullIndicadorPaginacion"S" if additional pages are available.
queryResultstring|nullResultadoConsulta"ConDatos" or "SinDatos".
foundRecordsarrayArray of matching invoice records as associative arrays.
paginationKeyarray|nullClavePaginacion — pass this in the next query to retrieve the next page.

EventDispatcherService

Namespace: eseperio\verifactu\services\EventDispatcherService Submits system events (RegistroEvento) to the AEAT VERI*FACTU event endpoint. Spanish law requires that certain computer system events — such as system startup, shutdown, and configuration changes — be reported to the tax authority via the EventosSIF SOAP operation. Direct use: Required for applications that must comply with the computer system event reporting obligation. This service is not called by VerifactuService.

dispatch(EventRecord $event, array $config): InvoiceResponse

Validates, serialises, signs, and submits an EventRecord to AEAT. Uses the same signing and SOAP infrastructure as VerifactuService.
event
EventRecord
required
The event record to dispatch. Must pass its own validate() check.
config
array
required
Configuration array with the following required keys:
  • wsdl — path or URL to the AEAT WSDL.
  • certPath — path to the digital certificate.
  • certPassword — certificate password.
Returns: InvoiceResponse — the parsed AEAT response for the event submission. Throws:
  • \InvalidArgumentExceptionEventRecord validation failed.
  • \SoapFault — SOAP-level error from the AEAT endpoint.
use eseperio\verifactu\services\EventDispatcherService;
use eseperio\verifactu\models\EventRecord;

$event = new EventRecord();
$event->versionId = '1.0';
$event->eventData = [
    'TipoEvento'        => 'Alta',
    'FechaHoraEvento'   => '2024-01-01T08:00:00+01:00',
    'DescripcionEvento' => 'System startup',
];

$response = EventDispatcherService::dispatch($event, [
    'wsdl'         => '/path/to/SistemaFacturacion.wsdl',
    'certPath'     => '/var/certs/empresa.pfx',
    'certPassword' => 's3cr3t',
]);
Internal execution steps:
  1. Validate EventRecord.
  2. Serialise to RegistroEvento XML via the internal buildEventXml() method.
  3. Sign with XmlSignerService::signXml().
  4. Create a SoapClient via SoapClientFactoryService (with a PEM temp file from CertificateManagerService).
  5. Call the EventosSIF SOAP operation.
  6. Parse and return via ResponseParserService::parseInvoiceResponse().

InvoiceSerializer

Namespace: eseperio\verifactu\services\InvoiceSerializer Converts the PHP model objects (InvoiceSubmission, InvoiceCancellation, InvoiceQuery) into DOMDocument instances that conform to the AEAT SuministroInformacion.xsd, SuministroLR.xsd, and ConsultaLR.xsd schemas. All monetary amounts are formatted to 2 decimal places with a dot separator; dates are converted from YYYY-MM-DD to the DD-MM-YYYY format required by AEAT. Direct use: Unlikely in application code. VerifactuService calls these methods automatically. You may call them directly for debugging, pre-validation, or integration testing.

Namespace constants

ConstantValue
SF_NAMESPACEhttps://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd
SFLR_NAMESPACEhttps://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd
QUERY_NAMESPACEhttps://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/ConsultaLR.xsd
DS_NAMESPACEhttp://www.w3.org/2000/09/xmldsig#

toInvoiceXml(InvoiceSubmission $invoice, bool $validate = false): \DOMDocument

Serialises an InvoiceSubmission to a RegistroAlta DOM document.
use eseperio\verifactu\services\InvoiceSerializer;

$dom = InvoiceSerializer::toInvoiceXml($invoice);
echo $dom->saveXML(); // Full XML string
When $validate = true the output is validated against SuministroInformacion.xsd; throws \Exception if invalid.

toCancellationXml(InvoiceCancellation $cancellation, bool $validate = false): \DOMDocument

Serialises an InvoiceCancellation to a RegistroAnulacion DOM document.
$dom = InvoiceSerializer::toCancellationXml($cancellation);

toQueryXml(InvoiceQuery $query, bool $validate = true): \DOMDocument

Serialises an InvoiceQuery to a ConsultaFactuSistemaFacturacion DOM document.
$dom = InvoiceSerializer::toQueryXml($query);
XSD validation is on by default for query serialisation ($validate = true).

wrapXmlWithRegFactuStructure(\DOMDocument $doc, string $nif, string $name, ?string $fechaFinVeriFactu = null): \DOMDocument

Wraps a RegistroAlta or RegistroAnulacion DOM document inside the top-level sfLR:RegFactuSistemaFacturacion envelope required by the SOAP body. Adds the Cabecera block with ObligadoEmision (issuer NIF and name) and optionally a RemisionVoluntaria / FechaFinVeriFactu element.
$wrappedDom = InvoiceSerializer::wrapXmlWithRegFactuStructure(
    $invoiceDom,
    'B12345678',
    'Mi Empresa, S.L.',
    null          // or a DD-MM-YYYY date string for voluntary submission end date
);

formatDate(string $date): string

Converts YYYY-MM-DD to DD-MM-YYYY. If the input is already in DD-MM-YYYY format (or any other format), it is returned unchanged.
InvoiceSerializer::formatDate('2024-06-15');  // "15-06-2024"
InvoiceSerializer::formatDate('15-06-2024');  // "15-06-2024" (no-op)

Build docs developers (and LLMs) love