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.
Overview
Verifactu::queryInvoices() sends a ConsultaFactuSistemaFacturacion SOAP request to AEAT
and returns the matching invoice records already stored in the AEAT ledger. This is useful for:
- Reconciling your local invoice database against what AEAT has accepted.
- Verifying the submission status of a specific invoice.
- Checking which invoices are on record for a given tax period.
- Paginating through large result sets.
The method accepts an InvoiceQuery model and returns a QueryResponse object.
Querying does not modify any data at AEAT. It is a read-only operation and can be called as
often as needed without side effects.
Building an InvoiceQuery
Required Fields
use eseperio\verifactu\models\InvoiceQuery;
$query = new InvoiceQuery();
$query->year = '2024'; // Tax year (Ejercicio) — four-digit string
$query->period = '07'; // Period (Periodo) — two-digit month ('01'–'12') or quarter
The period field follows the AEAT period notation. Supply the two-digit month string that
corresponds to the billing period you want to query (e.g. '07' for July, '01' for January).
Optional Filters
$query->seriesNumber = 'FA2024'; // Filter to invoices whose series starts with this value
$query->issueDate = '2024-07-15'; // Filter to a specific issue date (YYYY-MM-DD)
$query->externalRef = 'REF-QUERY-123'; // Match on your own external reference
Filter by Counterparty
Narrow results to invoices involving a specific buyer or seller NIF. Pass the NIF and
optionally the name:
$query->setCounterparty('A12345678', 'Cliente Ejemplo SL');
The method signature is:
$query->setCounterparty(string $nif, ?string $name = null): static
Filter by Issuer Party
To filter by a specific issuer NIF (useful for multi-obligor setups), call setIssuerparty():
$query->setIssuerparty('B12345678', 'Empresa Ejemplo SL');
The query must include the software system details, just like other operations:
$query->setSystemInfo('ERP Company', '1.0');
This is a simplified setter that accepts the system name and version:
$query->setSystemInfo(string $system, string $version): static
AEAT may return results in pages. To request a specific page, call setPaginationKey():
$query->setPaginationKey(1, 50); // page number, records per page
Retrieve the paginationKey from the previous QueryResponse and pass it back on the next
call to continue from where you left off. Check $result->paginationKey in the response
to get the key for the next page.
Validate and Submit
use eseperio\verifactu\Verifactu;
// Validate before sending
$validationResult = $query->validate();
if ($validationResult !== true) {
foreach ($validationResult as $property => $errors) {
echo "Error in '$property': " . implode(', ', $errors) . "\n";
}
exit;
}
// Submit the query
$result = Verifactu::queryInvoices($query);
Handling the QueryResponse
QueryResponse has no status constant. Check the queryResult string returned by AEAT directly — a successful query returns 'Correcto':
if ($result->queryResult === 'Correcto') {
echo "Records found: " . count($result->foundRecords) . "\n";
foreach ($result->foundRecords as $record) {
echo "Invoice: " . $record['NumSerieFactura'] . "\n";
echo "Date: " . $record['FechaExpedicionFactura'] . "\n";
echo "Issuer: " . $record['NombreRazonEmisor'] . " (" . $record['NIF'] . ")\n";
echo "Amount: " . $record['ImporteTotal'] . " EUR\n";
echo "CSV: " . $record['CSV'] . "\n";
echo "Status: " . $record['EstadoRegistro'] . "\n";
echo "---\n";
}
// Pagination — check if more records are available
if (!empty($result->paginationKey)) {
echo "More records available. Use paginationKey to fetch the next page.\n";
// Pass $result->paginationKey to your next query
}
} else {
echo "Query status: " . $result->queryResult . "\n";
echo "Pagination indicator: " . $result->paginationIndicator . "\n";
}
QueryResponse property | Type | Description |
|---|
queryResult | string | Result code returned by AEAT |
paginationIndicator | string | Whether pagination is in effect |
foundRecords | array | Array of matching invoice record arrays |
paginationKey | array|null | Key to pass for the next page of results |
header | array | Response header metadata |
period | array | The imputation period of the queried records |
Paginating Through All Results
$allRecords = [];
$page = 1;
do {
$query = new InvoiceQuery();
$query->year = '2024';
$query->period = '07';
$query->setSystemInfo('ERP Company', '1.0');
if ($page > 1) {
$query->setPaginationKey($page, 50);
}
$result = Verifactu::queryInvoices($query);
if ($result->queryResult === 'Correcto') {
$allRecords = array_merge($allRecords, $result->foundRecords ?? []);
}
$page++;
} while (!empty($result->paginationKey));
echo "Total records retrieved: " . count($allRecords) . "\n";
Complete Working Example
<?php
use eseperio\verifactu\Verifactu;
use eseperio\verifactu\models\InvoiceQuery;
use eseperio\verifactu\models\QueryResponse;
// Configure once at application bootstrap
Verifactu::config(
'/path/to/certificate.pfx',
'certificate-password',
Verifactu::TYPE_CERTIFICATE,
Verifactu::ENVIRONMENT_SANDBOX
);
$query = new InvoiceQuery();
// Required
$query->year = '2024';
$query->period = '07'; // July
// Optional filters
$query->seriesNumber = 'FA2024';
$query->issueDate = '2024-07-01';
// Filter by counterparty NIF
$query->setCounterparty('A12345678', 'Cliente Ejemplo SL');
// System info
$query->setSystemInfo('ERP Company', '1.0');
// Pagination (first page of 50 records)
$query->setPaginationKey(1, 50);
// Validate
$validationResult = $query->validate();
if ($validationResult !== true) {
print_r($validationResult);
exit;
}
// Submit
$result = Verifactu::queryInvoices($query);
// Process results
if ($result->queryResult === 'Correcto') {
$records = $result->foundRecords ?? [];
echo "Total records found in this page: " . count($records) . "\n";
foreach ($records as $record) {
echo "Invoice: " . ($record['NumSerieFactura'] ?? 'N/A') . "\n";
echo "Date: " . ($record['FechaExpedicionFactura'] ?? 'N/A') . "\n";
echo "Amount: " . ($record['ImporteTotal'] ?? 'N/A') . " EUR\n";
echo "CSV: " . ($record['CSV'] ?? 'N/A') . "\n";
echo "Status: " . ($record['EstadoRegistro'] ?? 'N/A') . "\n";
echo "---\n";
}
if (!empty($result->paginationKey)) {
echo "More records available — adjust setPaginationKey() to fetch the next page.\n";
}
} else {
echo "Query completed with status: " . $result->queryResult . "\n";
echo "Pagination indicator: " . $result->paginationIndicator . "\n";
}
Exception Handling
try {
$result = Verifactu::queryInvoices($query);
} catch (\InvalidArgumentException $e) {
// Validation failed — year/period missing, or invalid values
echo "Query validation error: " . $e->getMessage();
} catch (\SoapFault $e) {
// SOAP communication error
echo "SOAP error: " . $e->getMessage();
} catch (\Exception $e) {
echo "Unexpected error: " . $e->getMessage();
}