SAT validations

Stamping (the certification by a SAT-authorized provider that makes a CFDI valid) doesn't, on its own, make a CFDI (Mexico's electronic invoice) deductible. It may have been canceled after delivery, signed with a certificate that had already expired, or altered after it was signed. Its issuer may also appear on Lista 69-B (the SAT list of taxpayers presumed to issue invoices for nonexistent transactions, under Article 69-B of the Federal Tax Code). None of that shows on the PDF that reaches accounts payable. A SAT validation (SAT: Mexico's tax authority, Servicio de Administración Tributaria) checks the CFDI against the official sources at any time after it's issued. Fiscalapi runs seven independent criteria in a single call and returns a verdict for each one.

Use cases

Use caseWhat it solves
Accounts payableValidate each supplier CFDI when you receive it, and stop payment on the CFDIs that have no tax effect before you record a liability.
After-the-fact reconciliationDetect the cancellations that happened after the CFDI was delivered and recorded.
Supplier complianceCheck your supplier list against Lista 69-B and Lista 69-B Bis (the SAT list of taxpayers involved in a presumed improper transfer of the right to offset tax losses, under Article 69-B Bis of the Federal Tax Code) on a recurring basis, with the cutoff date of each query.
Document integrityConfirm that the stored XML is the same one that was signed and that its structure complies with Anexo 20 (the SAT technical standard that defines the CFDI: its XML structure, catalogs, and validation rules) before it enters your ERP.
AuditKeep the verdict of each criterion as support for the deduction or the IVA credit (acreditamiento, offsetting the VAT you paid against the VAT you charge).

Validating isn't stamping

Stamping certifies a CFDI when it's issued. Validation checks, at a later point, that the CFDI is still intact, active, and effective for tax purposes. They're two separate operations with separate balances that never mix: stamping uses stamps (one credit each, used each time you stamp a CFDI) and validation uses validation credits. See stamps.

RegulationWhat it governs
CFF (Código Fiscal de la Federación, Mexico's Federal Tax Code), Articles 29 and 29-ARequirements for issuing CFDIs.
Anexo 20 of the Resolución Miscelánea Fiscal (the SAT's annual tax rules)Structure of the CFDI XML and its complements (complemento, XML extensions the SAT defines for specific operations).
CFF, Article 69-BPresumed nonexistent transactions (EFOS, Empresas que Facturan Operaciones Simuladas, taxpayers that issue invoices for simulated transactions). Once the final list is published, the issuer's CFDIs have no tax effect and never had any, and the recipient has 30 business days from publication in the DOF (Diario Oficial de la Federación, Mexico's official gazette) to prove that the transaction took place or to correct its tax situation.
CFF, Article 69-B BisImproper transfer of the right to offset tax losses.

How it works

Send the CFDI and the list of criteria you want to run. Fiscalapi queries the official source of each criterion, charges one credit per requested criterion, and returns one result for each:

POST /api/v4/sat-validations
  ├── xml  (CFDI timbrado en Base64)  → admite los siete criterios
  └── tin  (RFC)                      → solo sat.blacklist.69b y sat.blacklist.69bbis
        └── validationTypes[]  →  resultado por criterio (type, status, passed)

Results come back in catalog order, not in the order you requested them. There's no pending status and nothing to poll: the response to the call is the final result.

Request parameters

The request body carries two things: what to check and which criteria to run on it.

FieldTypeRequiredWhat it is
xmlstringOne of the twoThe full stamped CFDI, Base64-encoded
tinstringOne of the twoThe RFC (Mexico's taxpayer ID, Registro Federal de Contribuyentes) to look up
validationTypesarray of stringsYesThe IDs of the criteria to run, with no empty or duplicate values

What to check: xml or tin

xml and tin are mutually exclusive: the request must include exactly one of them. Sending both, or neither, returns a 400 error. What you send determines which criteria you can request.

With xml, you check a specific CFDI and can request all seven criteria. For Lista 69-B and Lista 69-B Bis, Fiscalapi looks up the RFC in the cfdi:Emisor node of the CFDI itself.

With tin, you only look up the status of that RFC on the lists, so only sat.blacklist.69b and sat.blacklist.69bbis are accepted. Requesting any other criterion returns a 400 error. The RFC isn't matched against any CFDI: the response reflects only what the lists say about that RFC. Use it to check a supplier when you don't have an invoice from them to validate yet.

Limits

xml accepts up to 4,000,000 characters, and the request body up to 10 MB. The tin must have a valid RFC format.

The seven validation criteria

#CriterionIDRequested with
1XML structuresat.xml.structurexml
2Certificate validitysat.certificate.validityxml
3Issuer's digital seal (the issuer's signature over the CFDI, made with its CSD)sat.cfdi.selloxml
4SAT seal (the seal inside the digital tax stamp that certifies the CFDI)sat.tfd.selloxml
5CFDI statussat.cfdi.statusxml
6Lista 69-Bsat.blacklist.69bxml or tin
7Lista 69-B Bissat.blacklist.69bbisxml or tin

XML structure

Uses the SAT's official CFDI verification service to check that the document is well formed and complies with Anexo 20 for its version and with the schemas of the complements declared in schemaLocation. It detects missing required attributes, values outside the SAT catalogs, and invalid patterns.

Certificate validity

Checks that the issue date of the CFDI falls between the NotBefore and NotAfter dates of the issuer's certificate. A CFDI signed outside the validity period of its certificate isn't valid, even if its digital seal is.

Issuer's digital seal

Checks that the Sello attribute matches the original string (cadena original, the sequence of CFDI data that the digital seal signs) of the CFDI and the public key of the declared certificate. It confirms that the content wasn't altered after it was signed and that the signer holds the private key of that certificate.

SAT seal

Checks that the SelloSAT attribute of the digital tax stamp (Timbre Fiscal Digital, the SAT seal the PAC adds to a CFDI) matches the SAT certificate identified by NoCertificadoSAT. It confirms that the SAT issued the stamp through a PAC (Proveedor Autorizado de Certificación, a SAT-authorized provider that stamps CFDIs) and that the stamp wasn't forged or modified.

CFDI status

Queries the SAT's CFDI lookup service and reports the current status of the CFDI. It's the only criterion that reflects cancellations made after issue: a CFDI with all its seals correct can still be canceled.

Lista 69-B

Looks up the issuer's RFC in the full Lista 69-B and returns its current status as of the queried cutoff. It's the criterion with the most nuance, because it covers every stage of the procedure: Presunto is a risk alert in which the CFDIs still have tax effect, while Definitivo means they have none and starts the 30-business-day period for the recipient.

Lista 69-B Bis

Looks up the issuer's RFC in Lista 69-B Bis, which covers the improper transfer of the right to offset tax losses. It's relevant in related-party transactions and corporate restructurings.

Statuses of each criterion

Each criterion accepts only some statuses. A passing status returns passed: true.

StatusVerdictCriteria that return it
ValidoPassingXML structure, issuer's digital seal, and SAT seal
VigentePassingCertificate validity and CFDI status
NoListadoPassingLista 69-B and Lista 69-B Bis
DesvirtuadoPassingLista 69-B
SentenciaFavorablePassingLista 69-B and Lista 69-B Bis
InvalidoFailingXML structure, issuer's digital seal, and SAT seal
ExpiradoFailingCertificate validity
NoVigenteAunFailingCertificate validity
CanceladoFailingCFDI status
NoEncontradoFailingCFDI status
PresuntoFailingLista 69-B
DefinitivoFailingLista 69-B and Lista 69-B Bis
NoDisponibleFailingAll except certificate validity
OmitidoFailingAll

How to read a result

Each item in the response has three parts:

FieldWhat it is
passedThe binary verdict of the criterion: true if the status returned is a passing status for that criterion.
status.idThe specific status that produced that verdict. It's the value worth logging, because it tells apart cases that passed groups together.
status.detailsFree-form informational text with the facts of the case: the RFC and the cutoff date of the list, the certificate number, the SAT's response. It can be null, and your code must not parse it.

For example, Presunto and Definitivo both return passed: false, but they don't mean the same thing. An adverse verdict isn't an error: if the validation ran, the response is 200 even if the criterion doesn't pass.

Two statuses apply across criteria. They don't describe a tax fact, but how the criterion ran:

StatusWhat it meansWhat to do
NoDisponibleThe official source didn't respond, or there's no imported cutoff of the list. The criterion couldn't be determined.Retry later
OmitidoThe input didn't allow that criterion to be evaluated, for example a CFDI without a digital tax stamp.Check the CFDI you sent

An XML that isn't a stamped CFDI doesn't return a 400 error either. A malformed XML returns Invalido for the structure and Omitido for the rest. A readable but unstamped CFDI returns Omitido for the structure, both seals, and the status, while the certificate validity and the lists are still evaluated. In both cases, all the requested credits are charged.

Validation credits

Validations are charged in validation credits, a balance separate from the stamp balance.

  • Fiscalapi charges one credit per requested criterion, not one per call: requesting all seven costs seven.
  • You're charged even if the verdict is passed: false, and even if the status is NoDisponible or Omitido.
  • The charge is all or nothing and happens before execution: if the balance doesn't cover every requested criterion, none of them runs, nothing is used, and the API returns 403.
  • The catalog endpoints (list the criteria, get one by its ID, and list its statuses) are read-only and don't use credits.
ScenarioHTTPUses credits?
Full run, even if a criterion returns passed: false200Yes, one per criterion
NoDisponible or Omitido status200Yes
Malformed request: xml and tin both missing or both present, invalid Base64, unknown criterion400No
Insufficient balance403No
Nonexistent or inactive criterion on the catalog endpoints404No
Technical failure during execution500Refunded automatically
You cancel the request or the connection closesNo responseYes, the charge stands

Balance and top-up

The available balance of each person (any individual or legal entity registered in your tenant) is in availableValidationBalance of the people resource; availableBalance is the stamp balance. In the dashboard, they appear as Validaciones disponibles (Available validations) and Timbres disponibles (Available stamps).

Buy the credits in Tienda en línea (Store) in the dashboard. Then distribute them among the people in your tenant (the space in Fiscalapi that holds your issuers, recipients, credits, and data) from Catalogos > Personas (Catalogs > People), or through the API with the stamps endpoint and creditType: 2. The value 1, which is the default, transfers stamps.

Auditing usage

Each validation leaves a transaction in the same transaction log as stamps, which you query with List transactions. It's a consumption transaction, it has creditType: 2, and its comments list the IDs of the charged criteria, for example SAT: sat.xml.structure,sat.blacklist.69b. This way you reconcile credit spending criterion by criterion without instrumenting anything in your system.

Error responses also include a traceIdentifier, which is the same as the referenceId of the transaction: it's the value to cite when you report a problem. See response model and errors.

Test environment

In the test environment, the results are fictitious and random. At https://test.fiscalapi.com, the API doesn't query the SAT or evaluate the XML you send: it returns a status picked at random from the ones that criterion accepts. That's why two identical calls return different results, and details is always null.

You won't see NoDisponible or Omitido either. Credits are charged the same way. Use this environment only to learn the contract and test your integration: never use it as a source of tax truth or base a business decision on its results.

See environments for the credentials and the URL of each one.

Available in the SDKs

The five official SDKs expose SAT validations with the same surface: three catalog operations and one execution operation.

SDKAccessor
.NETfiscalApi.SatValidations
JavaScript / TypeScriptfiscalApi.satValidations
Pythonfiscalapi.sat_validations
JavafiscalApi.getSatValidationService()
PHP$fiscalApi->getSatValidationService()
Operation.NETPythonJavaScript / TypeScript, Java, and PHP
List validation typesGetTypesAsyncget_typesgetTypes
Get a type by its IDGetTypeByIdAsyncget_type_by_idgetTypeById
List the statuses of a typeGetStatusesAsyncget_statusesgetStatuses
ValidateValidateAsyncvalidatevalidate

All five expose the SatValidationTypeIds and SatValidationStatusIds constants; use them instead of literals. The examples of each operation in each language are in SAT validations, and the installation of each package is in SDKs.

Frequently asked questions

What's the difference between validating a CFDI and stamping it? Stamping certifies a CFDI when it's issued. Validation checks, at any later time, that the XML is still intact, active, and effective for tax purposes: seals, certificate, status at the SAT, and the issuer's standing on the Article 69-B lists.

Is a CFDI from an issuer on the final list still valid? It has no tax effect. Once the final Lista 69-B is published, the issuer's CFDIs are deemed, for everyone, to have no tax effect at all, and the recipient has 30 business days to prove that the transaction took place or to correct its tax situation.

How often are Lista 69-B and Lista 69-B Bis updated? Fiscalapi adds each official SAT publication. Each response from the list criteria includes in details the cutoff date of the list it queried, so your system knows what information it based its decision on.

Can I run only some criteria? Yes. validationTypes sets exactly which ones to run, and only those are charged. To check Lista 69-B and Lista 69-B Bis, send the issuer's RFC alone, without XML.

Related resources

Was this page helpful?