Saltar al contenido principal

Validaciones de Catálogos SAT

Endpoints para validar la compatibilidad entre diferentes campos de un CFDI antes de enviarlo. Esto permite que tu frontend valide los datos en tiempo real y evite errores de timbrado.

Beneficio Principal

Valida los datos antes de crear la factura para ofrecer una mejor experiencia de usuario y reducir rechazos del SAT.


Validar UsoCFDI con Régimen Fiscal

Verifica que el Uso de CFDI sea compatible con el Régimen Fiscal del receptor.

Endpoint

POST https://api.lummy.io/v1/catalogs/validate/uso-cfdi
EntornoURL
Producciónhttps://api.lummy.io/v1/catalogs/validate/uso-cfdi
Sandboxhttps://sandbox.lummy.io/v1/catalogs/validate/uso-cfdi

Request Body

{
"usoCfdi": "G03",
"regimenFiscal": "612"
}
{
"usoCfdi": string,requerido
Clave del Uso de CFDI según catálogo SAT c_UsoCFDI. Ejemplos: G03, I01, D01, etc.
"regimenFiscal": stringrequerido
Clave del Régimen Fiscal del receptor según catálogo SAT c_RegimenFiscal. Ejemplos: 612, 601, 605, etc.
}

Response

{
"valid": true,
"message": "El UsoCFDI 'G03' es válido para el Régimen Fiscal '612'"
}

Ejemplos de Código

curl -X POST "https://api.lummy.com/catalogs/validate/uso-cfdi" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "x-organization-id: ${ORG_ID}" \
-H "Content-Type: application/json" \
-d '{"usoCfdi": "G03", "regimenFiscal": "612"}'

Validar Código Postal

Verifica que un código postal exista y si tiene estímulo de franja fronteriza (para IVA del 8%).

Endpoint

POST https://api.lummy.io/v1/catalogs/validate/zip-code
EntornoURL
Producciónhttps://api.lummy.io/v1/catalogs/validate/zip-code
Sandboxhttps://sandbox.lummy.io/v1/catalogs/validate/zip-code

Request Body

{
"zipCode": "22000"
}
{
"zipCode": stringrequerido
Código postal de 5 caracteres que debe estar registrado en el catálogo del SAT. Se valida contra la base de datos oficial de códigos postales en México.
}

Response

{
"valid": true,
"message": "El código postal '22000' es válido y tiene estímulo de franja fronteriza (IVA 8%)",
"hasBorderStimulus": true,
"state": "Baja California"
}

Ejemplos de Código

curl -X POST "https://api.lummy.com/catalogs/validate/zip-code" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "x-organization-id: ${ORG_ID}" \
-H "Content-Type: application/json" \
-d '{"zipCode": "22000"}'
Franja Fronteriza

Los códigos postales con estímulo de franja fronteriza permiten aplicar IVA del 8% en lugar del 16%. Esto aplica para zonas fronterizas del norte de México.


Validar Moneda

Verifica que una moneda exista y retorna el número de decimales permitidos.

Endpoint

POST https://api.lummy.io/v1/catalogs/validate/currency
EntornoURL
Producciónhttps://api.lummy.io/v1/catalogs/validate/currency
Sandboxhttps://sandbox.lummy.io/v1/catalogs/validate/currency

Request Body

{
"currency": "USD"
}

Response

{
"valid": true,
"message": "La moneda 'USD' es válida con 2 decimales",
"decimals": 2,
"description": "Dólar Americano"
}

Ejemplos de Código

curl -X POST "https://api.lummy.com/catalogs/validate/currency" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "x-organization-id: ${ORG_ID}" \
-H "Content-Type: application/json" \
-d '{"currency": "USD"}'
Decimales por Moneda

Los montos de la factura deben respetar el número de decimales de la moneda. Por ejemplo:

  • MXN: 2 decimales
  • USD: 2 decimales
  • JPY: 0 decimales

Validar Régimen Fiscal

Verifica que un régimen fiscal exista y opcionalmente valida si aplica para Persona Física o Moral.

Endpoint

POST https://api.lummy.io/v1/catalogs/validate/regimen-fiscal
EntornoURL
Producciónhttps://api.lummy.io/v1/catalogs/validate/regimen-fiscal
Sandboxhttps://sandbox.lummy.io/v1/catalogs/validate/regimen-fiscal

Request Body

{
"regimenFiscal": "612",
"tipoPersona": "PF"
}
{
"regimenFiscal": string,requerido
Clave del Régimen Fiscal del emisor según catálogo SAT c_RegimenFiscal. Ejemplos: 612 (Personas Físicas con Actividades Empresariales), 601 (General de Ley Personas Morales), 605 (Personas Morales con Régimen de Intereses), etc.
"tipoPersona": stringopcional
Tipo de persona para validación adicional. Valores permitidos: "PF" (Persona Física) o "PM" (Persona Moral). Cuando se proporciona, valida que el régimen fiscal sea compatible con el tipo de persona especificado.
}

Response

{
"valid": true,
"message": "El Régimen Fiscal '612' es válido",
"appliesToPersonaFisica": true,
"appliesToPersonaMoral": false,
"description": "Personas Físicas con Actividades Empresariales y Profesionales"
}

Ejemplos de Código

curl -X POST "https://api.lummy.com/catalogs/validate/regimen-fiscal" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "x-organization-id: ${ORG_ID}" \
-H "Content-Type: application/json" \
-d '{"regimenFiscal": "612", "tipoPersona": "PF"}'

Validar Objeto de Impuesto

Verifica la congruencia entre el código de ObjetoImp y si el concepto incluye impuestos.

Endpoint

POST https://api.lummy.io/v1/catalogs/validate/tax-object
EntornoURL
Producciónhttps://api.lummy.io/v1/catalogs/validate/tax-object
Sandboxhttps://sandbox.lummy.io/v1/catalogs/validate/tax-object

Request Body

{
"taxObject": "02",
"hasTaxes": true
}
{
"taxObject": string,requerido
Código del objeto de impuesto según catálogo SAT c_ObjetoImp. Valores válidos: "01" (No objeto de impuesto), "02" (Sí objeto de impuesto), "03" (Sí objeto y no obligado al desglose), "04" (Sí objeto y no causa impuesto).
"hasTaxes": booleanrequerido
Booleano que indica si el concepto incluye impuestos. Debe coincidir con el código de ObjetoImp: "02" requiere true, "01" requiere false, "03" requiere false, "04" es flexible.
}

Reglas de ObjetoImp

CódigoDescripción¿Requiere Impuestos?
01No objeto de impuestoNo debe tener
02Si objeto de impuestoDebe tener
03Si objeto del impuesto y no obligado al desgloseNo debe tener
04Sí objeto del impuesto y no causa impuestoOpcional

Response

{
"valid": true,
"message": "La combinación de ObjetoImp e impuestos es válida"
}

Ejemplos de Código

curl -X POST "https://api.lummy.com/catalogs/validate/tax-object" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "x-organization-id: ${ORG_ID}" \
-H "Content-Type: application/json" \
-d '{"taxObject": "02", "hasTaxes": true}'

Cliente Completo de Validación

Aquí un ejemplo de clase cliente que encapsula todas las validaciones:

import axios, { AxiosInstance } from 'axios';

export class LummyValidationClient {
private client: AxiosInstance;

constructor(accessToken: string, orgId: string) {
this.client = axios.create({
baseURL: 'https://api.lummy.com/catalogs/validate',
headers: {
'Authorization': `Bearer ${accessToken}`,
'x-organization-id': orgId,
'Content-Type': 'application/json',
},
});
}

async validateUsoCfdi(usoCfdi: string, regimenFiscal: string) {
const { data } = await this.client.post('/uso-cfdi', { usoCfdi, regimenFiscal });
return data;
}

async validateZipCode(zipCode: string) {
const { data } = await this.client.post('/zip-code', { zipCode });
return data;
}

async validateCurrency(currency: string) {
const { data } = await this.client.post('/currency', { currency });
return data;
}

async validateRegimenFiscal(regimenFiscal: string, tipoPersona?: 'PF' | 'PM') {
const { data } = await this.client.post('/regimen-fiscal', { regimenFiscal, tipoPersona });
return data;
}

async validateTaxObject(taxObject: string, hasTaxes: boolean) {
const { data } = await this.client.post('/tax-object', { taxObject, hasTaxes });
return data;
}

// Validación completa para un formulario de factura
async validateInvoiceForm(form: {
usoCfdi: string;
regimenFiscal: string;
tipoPersona: 'PF' | 'PM';
zipCode: string;
currency: string;
}) {
const results = await Promise.all([
this.validateUsoCfdi(form.usoCfdi, form.regimenFiscal),
this.validateRegimenFiscal(form.regimenFiscal, form.tipoPersona),
this.validateZipCode(form.zipCode),
this.validateCurrency(form.currency),
]);

const errors = results.filter(r => !r.valid);

return {
valid: errors.length === 0,
errors: errors.map(e => ({ message: e.message, code: e.errorCode })),
};
}
}

// Uso
const client = new LummyValidationClient(accessToken, orgId);

// Validar formulario completo
const validation = await client.validateInvoiceForm({
usoCfdi: 'G03',
regimenFiscal: '612',
tipoPersona: 'PF',
zipCode: '06600',
currency: 'MXN',
});

if (!validation.valid) {
console.log('Errores de validación:', validation.errors);
}

Siguientes Pasos