Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/eclipxe13/CfdiUtils/llms.txt

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

The SAT operates a SOAP web service at https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc that lets you query the current status of any CFDI in real time. The response tells you whether a CFDI is currently valid (Vigente) or cancelled (Cancelado), whether it is eligible for cancellation, the status of any pending cancellation request, and whether the issuer is on the EFOS (simulated-operations) list. CfdiUtils implements this integration in the CfdiUtils\ConsultaCfdiSat namespace without requiring the WSDL file. The SAT stopped publishing the WSDL in October 2018, but the service itself continues to work and CfdiUtils constructs the SOAP call manually.
This feature requires PHP’s ext-soap extension. Verify it is enabled with php -m | grep soap.

WebService

CfdiUtils\ConsultaCfdiSat\WebService is the entry point. It wraps a SoapClient instance and exposes a single request() method.
<?php
use CfdiUtils\ConsultaCfdiSat\WebService;
use CfdiUtils\ConsultaCfdiSat\Config;

// Using defaults (10-second timeout, SSL peer verification enabled)
$service = new WebService();

// Using a custom Config
$config  = new Config(timeout: 30, verifyPeer: true);
$service = new WebService($config);

Config Options

timeout
int
default:"10"
Maximum seconds to wait for the SAT web service to respond.
verifyPeer
bool
default:"true"
Whether to verify the SAT server’s SSL certificate. Set to false only for troubleshooting — never in production.
serviceUrl
string
The SOAP endpoint URL. Override if you are routing through a reverse proxy.

Request Parameters

CfdiUtils\ConsultaCfdiSat\RequestParameters encapsulates all the data extracted from the CFDI’s QR code expression. The SAT web service accepts this same expression as its input.
<?php
public function __construct(
    string $version,    // '3.2', '3.3', or '4.0'
    string $rfcEmisor,
    string $rfcReceptor,
    string $total,      // may include thousands separator comma
    string $uuid,
    string $sello = '', // last 8 characters used in 3.3/4.0 expression
)
version
string
required
CFDI version: '3.2', '3.3', or '4.0'. Controls the format of the query expression built by expression().
rfcEmisor
string
required
RFC of the CFDI issuer.
rfcReceptor
string
required
RFC of the CFDI recipient.
total
string
required
Total amount of the CFDI. Commas used as thousands separators are stripped automatically.
uuid
string
required
The Folio Fiscal (UUID) from the Timbre Fiscal Digital complement.
sello
string
default:"\"\""
The CFDI’s Sello attribute. Only the last 8 characters are used (they always end in == for SHA-256 signatures). Required for CFDI 3.3 and 4.0 expressions; ignored for 3.2.

Building from a Cfdi Object

If you already have a parsed CfdiUtils\Cfdi object, use the static factory:
<?php
use CfdiUtils\Cfdi;
use CfdiUtils\ConsultaCfdiSat\RequestParameters;

$cfdi    = Cfdi::newFromString(file_get_contents('/cfdis/invoice.xml'));
$request = RequestParameters::createFromCfdi($cfdi);

StatusResponse

CfdiUtils\ConsultaCfdiSat\StatusResponse holds the four values returned by the SAT service plus convenience boolean methods.
getCode()
string
The raw CodigoEstatus response. Starts with S - for a successful lookup, or N - for a lookup failure.
getCfdi()
string
The CFDI state: Vigente, Cancelado, or No Encontrado.
getCancellable()
string
Whether the CFDI can be cancelled: No cancelable, Cancelable sin aceptación, or Cancelable con aceptación.
getCancellationStatus()
string
Status of any cancellation process: empty, Cancelado sin aceptación, En proceso, Plazo vencido, Cancelado con aceptación, or Solicitud rechazada.
getValidationEfos()
string
EFOS validation result: 200 (not listed) or 100 (listed as simulated-operations emitter).
Convenience booleans:
MethodReturns true when
responseWasOk()getCode() starts with 'S - '
isVigente()getCfdi() === 'Vigente'
isCancelled()getCfdi() === 'Cancelado'
isNotFound()getCfdi() === 'No Encontrado'
isEfosListed()getValidationEfos() === '100'

Make a Query

1

Gather the CFDI data

You need the RFC of the issuer, RFC of the recipient, total amount, UUID (Folio Fiscal), and the last 8 characters of the Sello (for CFDI 3.3 and 4.0).
2

Create RequestParameters

Build the parameters either from a Cfdi object or manually.
3

Instantiate WebService and call request()

Pass the RequestParameters to WebService::request() and receive a StatusResponse.
4

Inspect the response

Use responseWasOk(), isVigente(), isCancelled(), and the other accessors to interpret the result.

Example: Query from a CFDI file

<?php
use CfdiUtils\Cfdi;
use CfdiUtils\ConsultaCfdiSat\WebService;
use CfdiUtils\ConsultaCfdiSat\RequestParameters;

$cfdi    = Cfdi::newFromString(file_get_contents('/cfdis/invoice.xml'));
$request = RequestParameters::createFromCfdi($cfdi);

$service  = new WebService();
$response = $service->request($request);

if (! $response->responseWasOk()) {
    echo 'SAT lookup failed: ' . $response->getCode();
    exit;
}

echo 'Estado: '            . $response->getCfdi()               . PHP_EOL;
echo 'EsCancelable: '      . $response->getCancellable()         . PHP_EOL;
echo 'EstatusCancelacion: '. $response->getCancellationStatus()  . PHP_EOL;
echo 'ValidacionEFOS: '    . $response->getValidationEfos()      . PHP_EOL;

Example: Query from known data

<?php
use CfdiUtils\ConsultaCfdiSat\WebService;
use CfdiUtils\ConsultaCfdiSat\RequestParameters;

$request = new RequestParameters(
    '3.3',                                    // version
    'EKU9003173C9',                           // RFC emisor
    'COSC8001137NA',                          // RFC receptor
    '1,234.5678',                             // total (commas stripped automatically)
    'CEE4BE01-ADFA-4DEB-8421-ADD60F0BEDAC',  // UUID
    '... abcfe/1234=='                         // sello (last 8 chars used: 'e/1234==')
);

$service  = new WebService();
$response = $service->request($request);

echo $response->getCode();               // e.g. 'S - Comprobante obtenido satisfactoriamente'
echo $response->getCfdi();               // 'Vigente'
echo $response->getCancellable();        // 'Cancelable con aceptación'
echo $response->getCancellationStatus(); // 'En proceso'
echo $response->getValidationEfos();     // '200'

Understanding the Response

CodigoEstatus (query status)

Reflects whether the SAT was able to find the CFDI given the query expression — not the validity of the CFDI itself.
ValueMeaning
S - Comprobante obtenido satisfactoriamenteSAT found the CFDI; check getCfdi() for its state
N - 601: La expresión impresa proporcionada no es válidaThe query expression was malformed
N - 602: Comprobante no encontradoNo CFDI matched the provided data

Estado (CFDI state)

ValueMeaning
VigenteThe CFDI is currently valid
CanceladoThe CFDI has been cancelled
No EncontradoThe CFDI does not exist in the SAT database

EsCancelable

ValueMeaning
No cancelableCannot be cancelled (e.g. related documents exist)
Cancelable sin aceptaciónCan be cancelled immediately without recipient approval
Cancelable con aceptaciónCan be cancelled but requires the recipient to approve

EstatusCancelacion

ValueMeaning
(empty)No cancellation has been requested
Cancelado sin aceptaciónCancelled; recipient approval was not required
En procesoCancellation requested; awaiting recipient approval
Plazo vencidoCancelled automatically because the approval window expired
Cancelado con aceptaciónCancelled with explicit recipient approval
Solicitud rechazadaRecipient rejected the cancellation request

Mutually Exclusive States

CodigoEstatusEstadoEsCancelableEstatusCancelacionExplanation
N - ...***SAT could not identify the CFDI
S - ...Cancelado*Plazo vencidoCancelled by expiry of the approval window
S - ...Cancelado*Cancelado con aceptaciónCancelled with recipient consent
S - ...Cancelado*Cancelado sin aceptaciónCancelled without needing recipient consent
S - ...VigenteNo cancelable*Cannot be cancelled
S - ...VigenteCancelable sin aceptación*Cancellable, no request made yet
S - ...VigenteCancelable con aceptación(empty)Cancellable, no request made yet
S - ...VigenteCancelable con aceptaciónEn procesoCancellation requested, awaiting approval
S - ...VigenteCancelable con aceptaciónSolicitud rechazadaCancellation was rejected by recipient

EFOS (Empresas que Facturan Operaciones Simuladas)

EFOS is a SAT blacklist of companies suspected of issuing invoices for fictitious (“simulated”) operations — i.e., billing for goods or services that were never actually provided. Receiving a CFDI from an EFOS-listed emitter may have tax deduction implications. The web service returns a numeric code in ValidacionEFOS:
CodeMeaning
200Issuer was not found in the EFOS list
100Issuer was found in the EFOS list
Use isEfosListed() as a convenient check:
<?php
if ($response->isEfosListed()) {
    // Alert: issuer is on the EFOS blacklist
}
It is currently undocumented whether the EFOS status reflects the issuer’s standing at the moment of CFDI emission, at the moment it was reported to the SAT, or at the moment of the query. Consult your tax advisor for the applicable legal interpretation.

Build docs developers (and LLMs) love