Validaciones SAT
Una validación SAT verifica un CFDI timbrado contra los servicios oficiales del SAT: la estructura del XML, la vigencia del certificado del emisor, el sello del comprobante y el del timbre, el estatus del comprobante y los listados de los artículos 69-B y 69-B Bis del CFF. Cada verificación es un tipo de validación que se solicita de forma independiente.
Cada tipo solicitado consume un crédito de validación. El cobro es todo o nada: si el saldo no alcanza
para todos los tipos solicitados, no se ejecuta ninguno y la API responde 403. Los créditos de validación
son independientes de los timbres: se consultan en availableValidationBalance de cada persona
y se transfieren por el endpoint de timbres con creditType: 2.
Modelo tipo de validación
El modelo tipo de validación (SatValidationType) describe una de las verificaciones que Fiscalapi puede
ejecutar sobre un CFDI. Es un catálogo de solo lectura de siete tipos.
Propiedades
- Name
id- Type
- string?
- Description
Identificador del tipo de validación.
- Type
- enum:
- Values
- "sat.xml.structure""sat.certificate.validity""sat.cfdi.sello"
- Name
description- Type
- string?
- Description
Descripción de lo que verifica el tipo de validación.
Modelo resultado
El modelo resultado (SatValidationResult) es lo que devuelve la ejecución de una validación: un elemento por
cada tipo solicitado, siempre en el orden del catálogo.
Propiedades
- Name
type- Type
- object (SatValidationType)?
Tipo de validación que se ejecutó.
- Name
id- Type
- string?
- Description
Identificador del tipo de validación.
- Name
description- Type
- string?
- Description
Descripción de lo que verifica el tipo de validación.
- Name
status- Type
- object (SatValidationStatus)?
Estatus obtenido al ejecutar la validación.
- Name
id- Type
- string?
- Description
Identificador del estatus. Cada tipo de validación admite solo un subconjunto de estos valores: el que devuelve listar estatus de un tipo.
Un estatus aprobatorio da
passed: true; uno no aprobatorio,passed: false.- Type
- enum:
- Values
- "Valido""Vigente""NoListado"
- Name
description- Type
- string?
- Description
Descripción del estatus.
- Name
details- Type
- string?
- Description
Datos concretos del caso en texto libre, por ejemplo el número de certificado o la fecha de corte del listado consultado. Puede ser
null. Es informativo: no debe interpretarse programáticamente.
- Name
passed- Type
- boolean?
- Description
Veredicto que indica si el estatus obtenido es aprobatorio para ese tipo de validación.
Guarda cada respuesta: cada nueva consulta vuelve a consumir créditos de validación.
Listar tipos de validación
Este endpoint devuelve todos los tipos de validación activos, en el orden del catálogo. No recibe parámetros y no consume créditos.
Request
curl --location 'https://test.fiscalapi.com/api/v4/sat-validations' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'
Response
{
"data": [
{
"id": "sat.xml.structure",
"description": "Verifica mediante el servicio oficial de verificación de CFDI del SAT que el XML sea un documento bien formado y cumpla la estructura del Anexo 20 de su versión y la de los complementos declarados en schemaLocation. Detecta atributos obligatorios ausentes, valores fuera de catálogo y patrones inválidos."
},
{
"id": "sat.certificate.validity",
"description": "Comprueba que la fecha de emisión del CFDI esté comprendida entre NotBefore y NotAfter del certificado del emisor contenido en Certificado. Un CFDI firmado fuera de la vigencia del certificado carece de validez aunque el sello verifique."
},
{
"id": "sat.cfdi.sello",
"description": "Verifica mediante el servicio oficial de verificación de CFDI del SAT que el atributo Sello corresponda a la cadena original del comprobante y a la llave pública del certificado contenido en Certificado. Confirma que el contenido no fue alterado después de firmarse y que el firmante posee la llave privada de ese certificado."
},
{
"id": "sat.tfd.sello",
"description": "Verifica mediante el servicio oficial de verificación de CFDI del SAT que el atributo SelloSAT del TimbreFiscalDigital corresponda al certificado del SAT identificado por NoCertificadoSAT. Confirma que el timbre fue emitido por el SAT a través de un PAC y no fue fabricado ni modificado."
},
{
"id": "sat.cfdi.status",
"description": "Consulta ConsultaCFDIService del SAT con UUID, RFC emisor, RFC receptor y total, y reporta el estado actual del comprobante. Es la única validación que refleja cancelaciones posteriores a la emisión."
},
{
"id": "sat.blacklist.69b",
"description": "Busca el RFC del emisor en el listado completo del artículo 69-B CFF y devuelve la situación vigente. Definitivo implica que los CFDI del emisor no producen efectos fiscales y activa el plazo de 30 días hábiles para el receptor."
},
{
"id": "sat.blacklist.69bbis",
"description": "Busca el RFC del emisor en el listado del artículo 69-B Bis CFF (transmisión indebida del derecho a disminuir pérdidas fiscales) y devuelve la situación vigente. Relevante en operaciones con partes relacionadas y reestructuras."
}
],
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Obtener tipo de validación por ID
Este endpoint obtiene un tipo de validación por su ID. El ID contiene puntos y se envía tal cual, sin codificar. Devuelve 404 si el tipo no existe o está inactivo. No consume créditos.
Request
curl --location 'https://test.fiscalapi.com/api/v4/sat-validations/sat.xml.structure' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'
Response
{
"data": {
"id": "sat.xml.structure",
"description": "Verifica mediante el servicio oficial de verificación de CFDI del SAT que el XML sea un documento bien formado y cumpla la estructura del Anexo 20 de su versión y la de los complementos declarados en schemaLocation. Detecta atributos obligatorios ausentes, valores fuera de catálogo y patrones inválidos."
},
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Listar estatus de un tipo
Este endpoint devuelve los estatus que un tipo de validación puede tomar al ejecutarse: primero los
aprobatorios y, dentro de cada grupo, ordenados alfabéticamente por id. Es de solo lectura: no ejecuta
la validación ni consume créditos. La respuesta no
incluye el campo passed; esa correspondencia está en modelo resultado. Devuelve
404 si el tipo no existe o está inactivo.
Request
curl --location 'https://test.fiscalapi.com/api/v4/sat-validations/sat.xml.structure/statuses' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'
Response
{
"data": [
{
"id": "Valido",
"description": "Documento bien formado que cumple el XSD del Anexo 20 de su versión y los XSD de los complementos declarados en schemaLocation, según el verificador del SAT."
},
{
"id": "Invalido",
"description": "El documento no está bien formado o el verificador del SAT reporta que incumple el XSD del Anexo 20 o el de alguno de sus complementos."
},
{
"id": "NoDisponible",
"description": "El verificador del SAT no respondió o rechazó la consulta; la estructura no pudo determinarse y debe reintentarse."
},
{
"id": "Omitido",
"description": "No se evaluó porque el CFDI no contiene el complemento TimbreFiscalDigital; el verificador del SAT solo evalúa comprobantes timbrados."
}
],
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Validar
Este endpoint ejecuta las validaciones solicitadas y devuelve un resultado por cada tipo. Los resultados vuelven en el orden del catálogo, no en el orden en que los solicitaste.
Modelo
- Name
xml- Type
- string?
- Description
CFDI timbrado completo, codificado en Base64. Excluyente con
tin. Conxmlpuedes solicitar cualquier tipo de validación. Los listados 69-B y 69-B Bis consultan el RFC del nodocfdi:Emisor. Máximo 4,000,000 de caracteres; el tamaño máximo del cuerpo de la petición es de 10 MB.
- Name
tin- Type
- string?
- Description
RFC a consultar. Excluyente con
xml. Solo admite los tipossat.blacklist.69bysat.blacklist.69bbis. El RFC no se contrasta contra ningún CFDI: la respuesta refleja únicamente la situación del RFC enviado.
- Name
validationTypes- Type
- array of strings
- required
- Description
Tipos de validación a ejecutar. No admite elementos vacíos ni duplicados, y todos deben existir y estar activos.
- Type
- enum:
- Values
- "sat.xml.structure""sat.certificate.validity""sat.cfdi.sello"
En el ambiente de pruebas los resultados son ficticios y aleatorios. En
https://test.fiscalapi.com la API no consulta al SAT ni a su verificador, y ni siquiera evalúa el XML
que envías: devuelve un estatus elegido al azar de entre los que ese tipo admite. Por eso dos llamadas
idénticas dan resultados distintos y details siempre viene null.
Tampoco verás NoDisponible ni Omitido, ni aun enviando un XML inválido o sin timbrar. Los créditos se
cobran igual.
Este ambiente sirve únicamente para conocer el contrato y probar tu integración: nunca lo uses como
fuente de verdad fiscal ni tomes una decisión de negocio con su resultado. Para eso, usa producción. Los
details que ves en los ejemplos de esta página provienen de producción.
Envía xml o tin, nunca ambos ni ninguno. Un resultado adverso no es un error: si la validación se
ejecutó, la respuesta es 200 con passed: false.
Cada tipo solicitado consume un crédito de validación, incluso cuando el resultado es NoDisponible u
Omitido. Una petición mal formada devuelve 400 y no consume créditos; un saldo insuficiente devuelve 403
y tampoco los consume, porque el cobro ocurre después de validar la petición. Si la ejecución falla por un
problema técnico (error 500), el débito se reembolsa automáticamente como un movimiento de tipo reverso en
el registro de movimientos de timbres. En cambio, si cancelas la petición o se cierra la conexión, el consumo
se conserva y no recibes resultados: para entonces las consultas al SAT ya se pagaron.
Que el xml no sea un CFDI timbrado tampoco es un error 400: la respuesta es 200, se cobran todos los
créditos solicitados y cada tipo reporta lo que pudo determinar.
La tabla muestra el estatus de cada tipo con un XML mal formado o cuya raíz no es cfdi:Comprobante, y
con un CFDI legible pero sin timbrar. En el primer caso, details de sat.xml.structure trae el error
del lector.
| Tipo | XML mal formado | CFDI sin timbrar |
|---|---|---|
sat.xml.structure | Invalido | Omitido |
sat.certificate.validity | Omitido | Se evalúa |
sat.cfdi.sello | Omitido | Omitido |
sat.tfd.sello | Omitido | Omitido |
sat.cfdi.status | Omitido | Omitido |
sat.blacklist.69b | Omitido | Se evalúa |
sat.blacklist.69bbis | Omitido | Se evalúa |
Consulta errores y modelo de respuesta.
Request
curl --location 'https://test.fiscalapi.com/api/v4/sat-validations' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api_key>' \
--data-raw '{
"xml": "<xml-timbrado-en-base64>",
"validationTypes": [
"sat.xml.structure",
"sat.certificate.validity",
"sat.cfdi.sello",
"sat.tfd.sello",
"sat.cfdi.status",
"sat.blacklist.69b",
"sat.blacklist.69bbis"
]
}'
Response
{
"data": [
{
"type": {
"id": "sat.xml.structure",
"description": "Verifica mediante el servicio oficial de verificación de CFDI del SAT que el XML sea un documento bien formado y cumpla la estructura del Anexo 20 de su versión y la de los complementos declarados en schemaLocation. Detecta atributos obligatorios ausentes, valores fuera de catálogo y patrones inválidos."
},
"status": {
"id": "Valido",
"description": "Documento bien formado que cumple el XSD del Anexo 20 de su versión y los XSD de los complementos declarados en schemaLocation, según el verificador del SAT.",
"details": null
},
"passed": true
},
{
"type": {
"id": "sat.certificate.validity",
"description": "Comprueba que la fecha de emisión del CFDI esté comprendida entre NotBefore y NotAfter del certificado del emisor contenido en Certificado. Un CFDI firmado fuera de la vigencia del certificado carece de validez aunque el sello verifique."
},
"status": {
"id": "Vigente",
"description": "La fecha de emisión del CFDI está comprendida entre NotBefore y NotAfter del certificado del emisor.",
"details": "Emisión 2026-08-18T11:56:42 (hora de México); certificado 00001000000720012093 de MAX0611157H8 vigente del 2025-11-04 al 2029-11-04"
},
"passed": true
},
{
"type": {
"id": "sat.cfdi.sello",
"description": "Verifica mediante el servicio oficial de verificación de CFDI del SAT que el atributo Sello corresponda a la cadena original del comprobante y a la llave pública del certificado contenido en Certificado. Confirma que el contenido no fue alterado después de firmarse y que el firmante posee la llave privada de ese certificado."
},
"status": {
"id": "Valido",
"description": "El verificador del SAT confirma que el atributo Sello verifica contra la cadena original del comprobante con la llave pública del certificado del emisor.",
"details": null
},
"passed": true
},
{
"type": {
"id": "sat.tfd.sello",
"description": "Verifica mediante el servicio oficial de verificación de CFDI del SAT que el atributo SelloSAT del TimbreFiscalDigital corresponda al certificado del SAT identificado por NoCertificadoSAT. Confirma que el timbre fue emitido por el SAT a través de un PAC y no fue fabricado ni modificado."
},
"status": {
"id": "Valido",
"description": "El verificador del SAT confirma que el atributo SelloSAT verifica contra la cadena original del TimbreFiscalDigital con el certificado del SAT identificado por NoCertificadoSAT.",
"details": null
},
"passed": true
},
{
"type": {
"id": "sat.cfdi.status",
"description": "Consulta ConsultaCFDIService del SAT con UUID, RFC emisor, RFC receptor y total, y reporta el estado actual del comprobante. Es la única validación que refleja cancelaciones posteriores a la emisión."
},
"status": {
"id": "Vigente",
"description": "ConsultaCFDIService reporta el comprobante como Vigente; se incluyen EsCancelable y EstatusCancelacion devueltos por el SAT.",
"details": "Estado Vigente; CodigoEstatus S - Comprobante obtenido satisfactoriamente.; EsCancelable Cancelable con aceptación; EstatusCancelacion "
},
"passed": true
},
{
"type": {
"id": "sat.blacklist.69b",
"description": "Busca el RFC del emisor en el listado completo del artículo 69-B CFF y devuelve la situación vigente. Definitivo implica que los CFDI del emisor no producen efectos fiscales y activa el plazo de 30 días hábiles para el receptor."
},
"status": {
"id": "NoListado",
"description": "El RFC del emisor no figura en ninguna etapa del listado completo del artículo 69-B al corte indicado.",
"details": "RFC MAX0611157H8; corte del listado 2026-07-31"
},
"passed": true
},
{
"type": {
"id": "sat.blacklist.69bbis",
"description": "Busca el RFC del emisor en el listado del artículo 69-B Bis CFF (transmisión indebida del derecho a disminuir pérdidas fiscales) y devuelve la situación vigente. Relevante en operaciones con partes relacionadas y reestructuras."
},
"status": {
"id": "NoListado",
"description": "El RFC del emisor no figura en ninguna etapa del listado del artículo 69-B Bis al corte indicado.",
"details": "RFC MAX0611157H8; corte del listado 2026-06-05"
},
"passed": true
}
],
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Validar solo por RFC
Cuando solo necesitas saber si un RFC está en los listados 69-B y 69-B Bis del SAT, envía tin en lugar
de xml. Es el mismo endpoint y el mismo modelo.
En esta modalidad solo se admiten sat.blacklist.69b y sat.blacklist.69bbis: solicitar cualquier otro
tipo devuelve un error 400. Cada tipo solicitado consume un crédito, igual que la validación con XML, y
rige la misma advertencia que en validar: en el ambiente de pruebas el resultado es ficticio y
aleatorio, y no debe usarse para decidir nada.
Request
curl --location 'https://test.fiscalapi.com/api/v4/sat-validations' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api_key>' \
--data-raw '{
"tin": "XAXX010101000",
"validationTypes": [
"sat.blacklist.69b",
"sat.blacklist.69bbis"
]
}'
Response
{
"data": [
{
"type": {
"id": "sat.blacklist.69b",
"description": "Busca el RFC del emisor en el listado completo del artículo 69-B CFF y devuelve la situación vigente. Definitivo implica que los CFDI del emisor no producen efectos fiscales y activa el plazo de 30 días hábiles para el receptor."
},
"status": {
"id": "NoListado",
"description": "El RFC del emisor no figura en ninguna etapa del listado completo del artículo 69-B al corte indicado.",
"details": "RFC XAXX010101000; corte del listado 2026-07-31"
},
"passed": true
},
{
"type": {
"id": "sat.blacklist.69bbis",
"description": "Busca el RFC del emisor en el listado del artículo 69-B Bis CFF (transmisión indebida del derecho a disminuir pérdidas fiscales) y devuelve la situación vigente. Relevante en operaciones con partes relacionadas y reestructuras."
},
"status": {
"id": "NoListado",
"description": "El RFC del emisor no figura en ninguna etapa del listado del artículo 69-B Bis al corte indicado.",
"details": "RFC XAXX010101000; corte del listado 2026-06-05"
},
"passed": true
}
],
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Transferir créditos de validación
Transfiere créditos de validación entre personas con el endpoint de timbres y creditType en
2; con 1, el valor por omisión, se transfieren timbres. Los saldos de timbres y de validaciones nunca
se mezclan.
Modelo
- Name
fromPersonId- Type
- string
- required
- Description
ID de la persona origen que envía los créditos. Debe tener saldo suficiente de validaciones.
- Name
toPersonId- Type
- string
- required
- Description
ID de la persona destino que recibe los créditos.
- Name
amount- Type
- integer | number
- required
- Description
Cantidad de créditos a transferir. Debe ser mayor que cero.
- Name
comments- Type
- string?
- Description
Comentarios opcionales sobre la transferencia. Máximo 100 caracteres.
- Name
creditType- Type
- integer | number?
- expandible
- Description
Tipo de crédito a transferir.
- Type
- enum:
- Values
- 12
Default:1
Consulta el saldo resultante en availableValidationBalance del recurso personas; el de
timbres está en availableBalance.
Request
curl --location 'https://test.fiscalapi.com/api/v4/stamps' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api_key>' \
--data-raw '{
"fromPersonId": "1",
"toPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e",
"amount": 10,
"comments": "Créditos para validar CFDI",
"creditType": 2
}'
Response
{
"data": true,
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}