CFDI Status at the SAT
cfdi_statusQuery the SAT directly to confirm whether a Mexican CFDI invoice is still valid, cancelled or not found, using no credentials. Also returns EFOS blacklist and cancellation state.
Instructions
Ask the SAT whether an invoice actually exists and is still live. This queries the public ConsultaCFDIService SOAP endpoint — the same service the QR code printed on every Mexican invoice points at — so it needs no credentials, no CSD and no PAC contract.
Pass either the four values the SAT keys on (issuer RFC, receiver RFC, total, UUID) or the whole xml, in which case they are derived from it with the same reader parse_cfdi uses. Deriving them from the XML is the more reliable route: the total must be formatted exactly the way the printed-representation spec demands (six decimals, trailing zeros trimmed), and a hand-typed total is the single most common cause of a spurious 'No Encontrado'.
What comes back, each with its meaning spelled out:
Estado — Vigente / Cancelado / No Encontrado.
EsCancelable — whether the issuer can cancel it unilaterally, needs the receiver's approval, or cannot cancel it at all.
EstatusCancelacion — whether a cancellation is in progress, was accepted, was rejected, or lapsed.
ValidacionEFOS — whether the issuer appears on the SAT's definitive 69-B list of companies that invoice simulated operations.
CodigoEstatus — the service's own result code.
Fail-soft by design. The SAT publishes no rate limit, no SLA and no status page, and the endpoint does go down. On timeout, refusal or a malformed answer this returns available: false with the reason instead of raising — a failed lookup is a statement about the SAT, never about the invoice. Never report a document as invalid on the strength of an unreachable service. One retry, 10-second timeout.
Args (either shape):
xml (string), OR rfc_emisor + rfc_receptor + total + uuid (all strings).
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { available, unavailable_reason, endpoint, expression, attempts, elapsed_ms, source, status{codigo_estatus, query_outcome, estado, document_state, document_meaning, es_cancelable, cancellable_state, cancellable_meaning, estatus_cancelacion, cancellation_state, cancellation_meaning, validacion_efos, efos_state, efos_meaning, raw} | null, findings[] }.
Example: "Is this invoice still valid?" -> cfdi_status(xml="<cfdi:Comprobante …>").
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| xml | No | The complete CFDI XML. When given, the four query fields are derived from it and any values passed alongside are ignored. | |
| uuid | No | The fiscal folio (UUID) from the Timbre Fiscal Digital. Required unless `xml` is given. | |
| total | No | Invoice total exactly as written in the XML, e.g. '1160.00'. Required unless `xml` is given. | |
| rfc_emisor | No | Issuer's RFC. Required unless `xml` is given. | |
| rfc_receptor | No | Receiver's RFC. Required unless `xml` is given. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| source | Yes | ||
| status | Yes | ||
| attempts | Yes | ||
| endpoint | Yes | ||
| findings | Yes | ||
| available | Yes | ||
| elapsed_ms | Yes | ||
| expression | Yes | ||
| unavailable_reason | Yes |