Errores
Esta guía describe cómo se clasifican los errores de la API, qué indica cada código de estado y cómo interpretar las respuestas de error más comunes.
Antes de contactar a soporte, ten en cuenta que el 99% de los casos reportados corresponden a errores de integración. Revisa a fondo tu implementación antes de pedir ayuda.
Tipos de errores
Los errores se clasifican en dos niveles. Si falla alguna validación de nivel 1, la API detiene la solicitud y responde 400 (Bad Request) con el detalle de las fallas, sin ejecutar las validaciones de nivel 2.
1. Errores de nivel 1
Son las fallas de validación de la solicitud, que la API revisa antes de procesarla. Cada falla indica la propiedad que falló (propertyName) y un mensaje que depende de la regla aplicada. Usa la propiedad, y no el texto del mensaje, para identificar la falla en tu código (ver ValidationFailure).
Los mensajes están en español; por ejemplo, 'transpInternacId' no debe estar vacío. Algunos mensajes propios de reglas (ver Mensajes de validación del timbrado) y los errores de lectura del JSON, como un JSON mal formado o un valor de otro tipo, están en inglés.
2. Errores de nivel 2
Son las revisiones que el SAT exige para cumplir con el CFDI 4.0. Sus mensajes están en español y explican la causa según las especificaciones del SAT. Consulta la tabla de errores CFDI 4.0 para ver la lista completa.
Códigos de estado
La categoría del código de estado indica si la solicitud tuvo éxito. El cuerpo de la respuesta sigue el modelo de respuesta de FiscalAPI.
- Name
2xx- Description
La solicitud tuvo éxito.
- Name
4xx- Description
Error del cliente: hay un problema en la solicitud.
- Name
5xx- Description
Error del servidor. Es poco común; consulta Errores del servidor.
Recurso no encontrado
Cuando un endpoint busca un recurso por su id y el recurso no existe en tu cuenta, responde 404. El id puede ir en la ruta, como en Obtener factura por ID, o en el cuerpo, como invoiceId en Generar pdf por ID. Los endpoints con un mensaje propio para este caso lo indican en su sección (por ejemplo, certificados).
En los mensajes, <id> es el id enviado y <catalogName> es el nombre del catálogo en la ruta, que distingue mayúsculas y minúsculas: satpaymentforms no es SatPaymentForms.
| Estado | Cuándo ocurre | message | details |
|---|---|---|---|
| 404 | El recurso no existe en tu cuenta. | Sorry, it's not me, it's you. | No such resource for the given Id: <id> |
| 404 | La clave no existe en el catálogo, en Obtener registro por ID. | Sorry, it's not me, it's you. | No such resource for the given Id: <id> |
| 404 | El nombre del catálogo de la ruta no existe. | Sorry, it's not me, it's you. | No existe el catálogo '<catalogName>'. |
El nombre del catálogo se revisa en todas las rutas que lo llevan: GET /api/v4/catalogs/<catalogName>, Obtener registro por ID, Buscar en un catálogo, GET /api/v4/catalogs/<catalogName>/load y Listar catálogo de los catálogos de descarga masiva. Los nombres válidos son los que devuelven Listar catálogos y Listar catálogos de descarga masiva.
Claves de catálogo del SAT
Cuando un campo lleva una clave que no está en su catálogo del SAT, el endpoint responde 400 con una falla de validación en ese campo. El mensaje, en español, trae el valor recibido y el nombre del catálogo, sin la lista de claves.
La regla aplica a las facturas (POST /api/v4/invoices) y a su cancelación, que rechaza el motivo sin llamar al PAC. También aplica a los productos, las personas (emisores y receptores) y los datos de empleado y empleador. Consulta las claves válidas con la API de catálogos.
| Campo | Mensaje |
|---|---|
| Forma general | <El dato> '<valor>' no existe en el catálogo <c_Catálogo> del SAT. |
PaymentFormCode (ejemplo) | La forma de pago '98' no existe en el catálogo c_FormaPago del SAT. |
CancellationReasonCode | El motivo de cancelación '<valor>' no existe en el catálogo c_MotivoCancelacion del SAT. |
Cada campo responde una sola falla: en los campos obligatorios con esta regla (por ejemplo, versionCode, typeCode, los impuestos o las claves de nómina), un valor vacío o ausente responde solo el mensaje de campo vacío. Los campos siguientes tienen un mensaje propio, distinto de la forma general:
| Campo | Mensaje |
|---|---|
versionCode | La versión de CFDI '<valor>' no es válida: usa 4.0. |
taxFlagCode de los impuestos del concepto, del documento pagado y de los impuestos locales (complement.localTaxes); taxFlagId en productos | La naturaleza del impuesto '<valor>' no es válida: usa T (traslado) o R (retención). |
expeditionZipCode, recipient.zipCode y el código postal a cuenta de terceros | El código postal '<valor>' debe tener 5 caracteres (catálogo c_CodigoPostal del SAT). |
recipient.zipCode | El código postal '<valor>' debe tener 5 dígitos (catálogo c_CodigoPostal del SAT). |
recipient.zipCode, si falta | El código postal es obligatorio. |
itemCode del concepto y de sus partes | La clave de producto o servicio '<valor>' debe tener 8 caracteres (catálogo c_ClaveProdServ del SAT). |
currencyCode de una factura de pago (P) | La moneda de un comprobante de pago debe ser XXX. |
Moneda del pago y de cada factura pagada (complement.payment) con XXX | La moneda de un pago o de un documento pagado no puede ser XXX. |
| Catálogos de Nómina 1.2: tipo de nómina, percepción, horas extra, otro pago, deducción e incapacidad; en los datos de empleado y empleador, tipo de contrato, régimen, periodicidad de pago, entidad federativa, riesgo de puesto, banco, tipo de jornada y origen del recurso. Solo se aceptan las claves vigentes. | La clave '<valor>' no existe en el catálogo <c_Catálogo> del SAT o ya no está vigente. |
Sindicalizado (satUnionizedStatusId) | El valor '<valor>' de Sindicalizado no es válido: usa Sí o No. |
Valores que no caben en la factura
Al timbrar (POST /api/v4/invoices, por valores o por referencias, con cualquier tipo de factura y complemento) y al calcular (POST /api/v4/invoices/calculate), Fiscalapi arma la factura que guardaría y revisa que cada valor quepa en ella. Un texto no puede ser más largo que su máximo, y un importe o una cantidad, redondeado a sus decimales, no puede tener más dígitos enteros que los admitidos. Por ejemplo, la cantidad del concepto y el monto del pago admiten 12: valores menores que 1000000000000.
Si un valor no cabe, el endpoint responde 400 con una falla de validación por cada valor, sin timbrar y sin consumir timbre. Al timbrar, la revisión ocurre antes de cobrar el timbre y de llamar al PAC; el cálculo nunca timbra ni consume timbre.
| Valor | errorMessage | attemptedValue |
|---|---|---|
| Texto | Admite como máximo <n> caracteres y se recibieron <m>. | null (el texto puede ser un dato personal) |
| Importe o cantidad | Admite como máximo <d> dígitos enteros (valores menores que <10^d>); se recibió <valor>. | El número recibido |
En esta falla, propertyName es la ruta del dato en la factura guardada, no la del campo del request:
| Campo del request | propertyName |
|---|---|
items[0].quantity | InvoiceItems[0].Quantity |
complement.payment.amount | InvoicePayment.Amount |
complement.payroll.deductions[0].code | Payroll.Deductions[0].Code |
Otras rutas posibles son, por ejemplo:
| Dato | propertyName |
|---|---|
| Documento pagado | InvoicePayment.PaidInvoices[0].Number |
| Percepción de nómina | Payroll.Earnings.Earnings[0].Concept |
| Datos de empleado | InvoiceRecipient.EmployeeData.Curp |
| Datos de empleador | InvoiceIssuer.EmployerData.EmployerRegistration |
| Carta Porte | CartaPorte.Mercancias[0].ClaveUnidad |
| Comercio Exterior | ComercioExterior.Emisor.Domicilio.Colonia |
Las reglas propias de los campos del request (por ejemplo, el correo del receptor de hasta 256 caracteres o itemSku de hasta 100) responden antes, con la falla en el campo del request.
Decimales de importes, cantidades y tasas
Al timbrar (POST /api/v4/invoices, por valores o por referencias) y al calcular (POST /api/v4/invoices/calculate), los importes, cantidades y tasas que van tal cual al XML admiten como máximo los decimales que el SAT define para su atributo (XSD del CFDI 4.0 y de sus complementos). Un valor con más decimales responde 400 con una falla de validación por cada valor, antes de cobrar el timbre y de llamar al PAC:
propertyName | errorMessage | attemptedValue |
|---|---|---|
La ruta del campo en el request, en PascalCase (por ejemplo, Items[0].Discount) | '<campo>' admite como máximo <n> decimales (se recibieron <m>): redondéalo antes de enviarlo; FiscalAPI no lo redondea. | El número recibido |
Ejemplo: un descuento calculado en JavaScript como 0.1 + 0.2, en Items[0].Discount | 'discount' admite como máximo 6 decimales (se recibieron 17): redondéalo antes de enviarlo; FiscalAPI no lo redondea. | 0.30000000000000004 |
Fiscalapi no redondea el valor: redondéalo en tu sistema al número de decimales que corresponda antes de enviarlo. Por ejemplo, a 6 decimales:
| Lenguaje | Redondeo |
|---|---|
| JavaScript | Number(x.toFixed(6)) |
| PHP | round($x, 6) |
| Python | Decimal.quantize |
| Java | setScale(6, RoundingMode.HALF_UP) |
| .NET | Math.Round(x, 6) |
Solo cuentan los decimales significativos, no los ceros finales. Por ejemplo, se aceptan 0.16000000 en taxRate y un tipo de cambio de 1.0000000 con moneda MXN. Los límites, según el atributo del XML, son:
| Campos | Decimales | Atributo del SAT |
|---|---|---|
items[n].quantity y items[n].parts[n].quantity | 6 | Cantidad |
items[n].unitPrice, items[n].discount y items[n].parts[n].unitPrice | 6 | ValorUnitario y Descuento (t_Importe) |
items[n].itemTaxes[n].taxRate | 6 | TasaOCuota |
exchangeRate | 6 | TipoCambio |
complement.payment.exchangeRate | 6 | TipoCambioP |
complement.payment.amount | 6 | Monto |
complement.payment.paidInvoices[n].previousBalance, paymentAmount y remainingBalance | 6 | ImpSaldoAnt, ImpPagado e ImpSaldoInsoluto |
complement.payment.paidInvoices[n].subTotal y paidInvoiceTaxes[n].base | 6 | BaseDR |
complement.payment.paidInvoices[n].paidInvoiceTaxes[n].taxRate | 6 | TasaOCuotaDR |
complement.payment.paidInvoices[n].equivalence | 10 | EquivalenciaDR |
complement.payroll.daysPaid | 3 | NumDiasPagados (ver la nota de abajo) |
complement.payroll.earnings.earnings[n].taxedAmount y exemptAmount | 2 | ImporteGravado e ImporteExento (t_ImporteMXN) |
complement.payroll.earnings.earnings[n].stockOptions.marketPrice y grantPrice | 6 | ValorMercado y PrecioAlOtorgarse |
complement.payroll.earnings.earnings[n].overtime[n].amountPaid | 2 | ImportePagado |
complement.payroll.earnings.otherPayments[n].subsidyCaused, y balanceCompensation.favorableBalance y remainingFavorableBalance | 2 | SubsidioCausado, SaldoAFavor y RemanenteSalFav |
complement.payroll.earnings.retirement.totalOneTime, totalInstallments y dailyAmount | 2 | Atributos de JubilacionPensionRetiro |
complement.payroll.earnings.retirement.accumulableIncome y nonAccumulableIncome | 2 | Atributos de JubilacionPensionRetiro |
complement.payroll.earnings.severance.totalPaid y lastMonthlySalary | 2 | Atributos de SeparacionIndemnizacion |
complement.payroll.earnings.severance.accumulableIncome y nonAccumulableIncome | 2 | Atributos de SeparacionIndemnizacion |
complement.payroll.deductions[n].amount | 2 | Importe de la deducción |
complement.payroll.disabilities[n].monetaryAmount | 2 | ImporteMonetario |
recipient.employeeData.baseSalaryForContributions e integratedDailySalary | 2 | SalarioBaseCotApor y SalarioDiarioIntegrado |
recipient.employeeData.timePercentage | 3 | PorcentajeTiempo |
issuer.employerData.ownResourceAmount | 2 | MontoRecursoPropio |
La regla aplica al campo aunque, en una factura concreta, su valor no llegue al XML (por ejemplo, totalInstallments y dailyAmount junto con totalOneTime). No aplica a los campos que Fiscalapi redondea al armar el XML (el importe de otros pagos de nómina, los impuestos locales y los importes de Comercio Exterior) ni a los de Carta Porte y Comercio Exterior, que validan sus decimales con su propio mensaje.
El campo daysPaid (días pagados de la nómina) acepta un entero o hasta 3 decimales. Fiscalapi lo escribe en el XML como lo pide el SAT: entero, o con exactamente 3 decimales.
| Valor enviado | Resultado |
|---|---|
15.5 | Se timbra como 15.500. |
15.0 | Se timbra como 15. |
15.2083333 | Responde la falla de decimales: tiene más de 3 decimales significativos. |
Fiscalapi escribe algunos números con su propia escala, como la tasa o cuota y el tipo de cambio con MXN; por eso los ceros de más en esos campos no llegan al XML. Un importe que va tal cual al XML con ceros de más (por ejemplo, 200.0000000 en unitPrice) lo rechaza el PAC con CFDI40999: envía como máximo los decimales del atributo.
Mensajes de validación del timbrado
Al timbrar (POST /api/v4/invoices, por valores o por referencias) y al calcular (POST /api/v4/invoices/calculate), los mensajes de validación están en español y nombran el campo como en la API: en camelCase, igual que en el JSON. Los demás endpoints nombran el campo con el nombre de la propiedad separado en palabras.
El campo de la falla (propertyName) es la ruta del dato en el request, en PascalCase (por ejemplo, Items[0].ItemTaxes[0].TaxCode). Úsalo, y no el texto, para identificar la falla (ver ValidationFailure).
| Caso | Mensaje (ejemplo) |
|---|---|
| Campo vacío, al timbrar | 'taxCode' no debería estar vacío. |
| Valor fuera de rango, al timbrar | 'quantity' debe ser mayor que '0'. |
| Campo obligatorio que falta dentro de un complemento | 'code' no debe estar vacío. |
| Campo vacío, en los demás endpoints | 'Cancellation Reason Code' no debería estar vacío. |
Estas reglas del timbrado tienen un mensaje propio. En los mensajes, <campo> es el nombre del campo como en la API; por ejemplo, 'date'. <régimen> y <uso> son las claves del receptor, y el tipo de persona (moral o física) es el que corresponde a la longitud de su RFC.
Campo (propertyName) | Mensaje |
|---|---|
Issuer.Tin, Recipient.Tin | 'tin' no tiene el formato de RFC del SAT: 3 letras (persona moral) o 4 (persona física), la fecha AAMMDD y 3 caracteres de homoclave. |
Number | 'number' (folio) debe tener de 1 a 40 caracteres sin el carácter '|'; si se omite (o va null o vacío), se genera automáticamente. |
Date, Complement.Payment.PaymentDate y Complement.CartaPorte.Ubicaciones[n].FechaHoraSalidaLlegada | '<campo>' es obligatorio y debe ser una fecha con el formato yyyy-MM-ddTHH:mm:ss. |
Complement.Payroll.PaymentDate, InitialPaymentDate y FinalPaymentDate | '<campo>' es obligatorio y debe ser una fecha con el formato yyyy-MM-dd. |
Items (facturas de tipo I, E y T) | items debe tener al menos un concepto en los comprobantes de tipo I, E y T. |
Items[n].Description | 'description' debe tener de 1 a 1000 caracteres y no puede contener el carácter '|'. |
TaxRate de los impuestos del concepto y del documento pagado | 'taxRate' (tasa o cuota) debe ser mayor o igual que 0. |
TaxTypeCode de una retención | Una retención (taxFlagCode R) no puede tener 'taxTypeCode' Exento. |
ExchangeRate y Complement.Payment.ExchangeRate, con moneda MXN | Con la moneda MXN, 'exchangeRate' (tipo de cambio) debe ser 1. |
ExchangeRate y Complement.Payment.ExchangeRate, con otra moneda | Con una moneda distinta de MXN, 'exchangeRate' (tipo de cambio) debe ser el del día de la operación (mayor que 0). |
ExchangeRate y Complement.Payment.ExchangeRate, con moneda XXX | Con la moneda XXX, 'exchangeRate' (tipo de cambio) no aplica: se omite (o se envía 1 o 0). |
Complement (el mensaje depende del tipo de factura; por ejemplo, en un pago) | Un comprobante de tipo P (pago) requiere complement.payment y no admite otro complemento. |
Complement (por ejemplo, en un ingreso) | Un comprobante de tipo I (ingreso) no lleva complement o solo lleva complement.localTaxes, complement.cartaPorte o complement.comercioExterior. |
GlobalInformation.Year | 'year' debe ser el año de la fecha del comprobante (<año>) o uno de los 5 anteriores. |
RelatedInvoices | Todos los 'relatedInvoices' deben tener el mismo relationshipTypeCode. |
Recipient.TaxRegimeCode con el RFC genérico | Con el RFC genérico (XAXX010101000 o XEXX010101000) el régimen fiscal del receptor (taxRegimeCode) debe ser 616 (CFDI40159). |
Recipient.ZipCode con el RFC genérico | Con el RFC genérico (XAXX010101000 o XEXX010101000) el código postal del receptor (zipCode) debe ser el lugar de expedición (expeditionZipCode) (CFDI40149). |
Recipient.TaxRegimeCode según el tipo de persona | El régimen fiscal '<régimen>' del receptor (taxRegimeCode) no aplica a una persona moral (RFC de 12 caracteres) según el catálogo c_RegimenFiscal (CFDI40158). |
Recipient.CfdiUseCode según el tipo de persona | El uso de CFDI '<uso>' del receptor (cfdiUseCode) no aplica a una persona física (RFC de 13 caracteres) según el catálogo c_UsoCFDI (CFDI40161). |
Recipient.CfdiUseCode según el régimen | El uso de CFDI '<uso>' del receptor (cfdiUseCode) no admite el régimen fiscal '<régimen>' (taxRegimeCode) según el catálogo c_UsoCFDI (CFDI40161). |
GlobalInformation en un ingreso a XAXX010101000 | Un ingreso a XAXX010101000 'PUBLICO EN GENERAL' es una factura global: globalInformation es obligatorio (CFDI40130). |
Recipient.ForeignTin | 'foreignTin' (NumRegIdTrib) debe tener de 1 a 40 caracteres. |
Recipient.Email | 'email' no es un correo electrónico válido. |
Issuer.TaxCredentials (y TaxCredentials de la cancelación por valores) | Debes proporcionar exactamente 2 credenciales fiscales (sellos SAT): una de fileType=0 (CertificateCsd) y otra de fileType=1 (PrivateKeyCsd). |
Cada credencial de Issuer.TaxCredentials o TaxCredentials | 'fileType' '<valor>' no es un tipo de archivo válido. |
Cada credencial de Issuer.TaxCredentials o TaxCredentials | 'password' es obligatorio para la llave privada. |
Documento pagado (Complement.Payment.PaidInvoices[n]) | 'equivalence' debe ser 1 cuando la moneda del documento pagado es la del pago. |
Documento pagado (Complement.Payment.PaidInvoices[n]) | 'subTotal' debe ser mayor que 0 cuando un impuesto del documento pagado tiene base 0 (base 0 toma el subTotal). |
Base de los impuestos del documento pagado | 'base' debe ser mayor o igual que 0 (0 toma el subTotal del documento pagado). |
Base de los impuestos del documento pagado, con taxTypeCode Cuota | Un impuesto con taxTypeCode Cuota requiere 'base' (unidades): el subTotal del documento pagado es un importe. |
Impuestos locales (Complement.LocalTaxes) | 'taxes' requiere al menos un impuesto local. |
Impuestos locales (Complement.LocalTaxes) | 'taxName' (nombre del impuesto local) es obligatorio; p. ej., ISN o CEDULAR. |
Impuestos locales (Complement.LocalTaxes) | 'taxRate' debe ser mayor que 0; p. ej., 0.030000 para 3 %. |
taxFlagCode de los impuestos locales | El texto de Claves de catálogo del SAT. |
Carta Porte (Complement.CartaPorte) | 'ubicaciones' requiere al menos 2 ubicaciones. |
Carta Porte (Complement.CartaPorte) | Se permiten como máximo 2 remolques. |
Comercio Exterior (Complement.ComercioExterior) | 'certificadoOrigen' debe ser 0 (no funge) o 1 (funge como certificado de origen). |
Comercio Exterior (Complement.ComercioExterior) | 'mercancias' requiere al menos una mercancía. |
Comercio Exterior (Complement.ComercioExterior) | 'domicilios' del destinatario requiere al menos un domicilio. |
Una factura con más de 1,500 conceptos responde 400 sin falla de validación, tanto al timbrar como al calcular:
| Estado | Cuándo ocurre | details |
|---|---|---|
| 400 | La factura tiene más de 1,500 conceptos. | Una factura admite como máximo 1500 conceptos (items). |
Están en inglés los mensajes de catálogo de Carta Porte y Comercio Exterior, los de los archivos de certificados y los del lector de JSON (JSON mal formado o un valor de otro tipo). Por ejemplo:
| Origen | Mensaje |
|---|---|
| Catálogos de Carta Porte y Comercio Exterior | <Campo> must be a valid c_<Catálogo> value. |
| Catálogos de Carta Porte y Comercio Exterior (ejemplo) | NumEstacionId must be a valid c_Estaciones value. |
| Archivos de certificados (ejemplo) | The certificate (.cer) belongs to RFC <rfc>, but the RFC of <dueño> is <rfc>. Use the certificate issued to that RFC. |
Elementos null en listas
Cada elemento de una lista de objetos del cuerpo debe ser un objeto. Un elemento null, como en "relatedInvoices": [null] o "productTaxes": [{ ... }, null], responde 400 con una falla de validación por cada elemento null:
| Campo de la falla | Valor |
|---|---|
propertyName | La ruta del elemento, con su posición desde 0; por ejemplo, Items[1] o Complement.Payroll.Earnings.Earnings[0]. |
errorMessage | '<campo>' no admite elementos null: cada elemento debe ser un objeto. |
attemptedValue | null |
Esta revisión corre antes que las demás validaciones y antes de llamar al PAC: la respuesta trae solo las fallas de los elementos null, sin timbrar ni consumir timbre. Si además el cuerpo no se puede leer (por ejemplo, un valor de otro tipo), responde solo la falla de lectura.
Al timbrar y al calcular, el mensaje nombra el campo como en la API, en camelCase. Los demás endpoints lo nombran con el nombre de la propiedad separado en palabras.
| Endpoint | Listas | propertyName | Mensaje (ejemplo) |
|---|---|---|---|
Timbrado (POST /api/v4/invoices, por valores y por referencias) y cálculo (POST /api/v4/invoices/calculate) | Todas las listas de objetos de la factura y sus complementos: por ejemplo, conceptos, impuestos del concepto, facturas relacionadas, credenciales del emisor, documentos pagados, percepciones y deducciones de nómina, ubicaciones de Carta Porte o mercancías de Comercio Exterior | RelatedInvoices[0] | 'relatedInvoices' no admite elementos null: cada elemento debe ser un objeto. |
| Crear producto y Actualizar producto | productTaxes | ProductTaxes[n] | 'Product Taxes' no admite elementos null: cada elemento debe ser un objeto. |
| Cancelar factura, por valores y por referencias | taxCredentials | TaxCredentials[n] | 'Tax Credentials' no admite elementos null: cada elemento debe ser un objeto. |
Un elemento null responde solo esta falla, en su posición, también en las listas que tienen su propia regla: taxCredentials (el par de certificados y la lista vacía), paidInvoices y paidInvoiceTaxes (la lista vacía) y las ubicaciones de Carta Porte (mínimo 2).
Las listas de textos (por ejemplo, validationTypes de las validaciones SAT) conservan su propia regla. El campo metadata es un diccionario y no una lista: acepta valores null.
Certificados y llaves privadas
Los endpoints que reciben una llave privada (archivo .key) con su contraseña la abren antes de usarla. Si la contraseña no abre la llave, responden 400 con una falla de validación en el campo de la contraseña. La misma falla sale si el archivo enviado como llave no es una llave privada: la lectura de la llave no distingue los dos casos. La revisión ocurre antes de llamar al PAC y sin consumir timbre.
| Campo de la falla | Valor |
|---|---|
errorMessage | La contraseña de la llave privada (.key) es incorrecta o el archivo no es una llave privada. |
attemptedValue | null: la contraseña no se devuelve. |
propertyName | Depende del endpoint (ver la tabla siguiente). |
| Endpoint | propertyName |
|---|---|
Timbrado con el emisor por valores (issuer.taxCredentials) | Issuer.TaxCredentials[<n>].Password, con la posición de la llave en la lista (por ejemplo, Issuer.TaxCredentials[1].Password) |
Subir certificados con una llave privada CSD (fileType 1) | Password |
Subir certificados con una llave privada FIEL (fileType 3) | Password |
| Firmar Carta Manifiesto | Password |
La cancelación por valores (con taxCredentials) no abre la llave: la envía al PAC, que responde su propio error si la contraseña no corresponde.
Otros errores de certificados y llaves:
| Estado | Cuándo ocurre | message | details |
|---|---|---|---|
| 400 | Un certificado (.cer) o una llave privada (.key) recibidos no se pueden leer, en un flujo sin la revisión anterior; por ejemplo, un .cer ilegible al firmar la Carta Manifiesto. | Sorry, it's not me, it's you. | No se pudo leer el certificado (.cer) o la llave privada (.key). |
| 500 | Fiscalapi no puede descifrar un dato protegido que guarda; por ejemplo, la contraseña de los certificados de una persona al timbrar o cancelar por referencias, o al obtener los certificados por defecto. | Sorry, it's not you, it's me. | No pudimos descifrar un dato protegido del servidor. Escríbenos a soporte@fiscalapi.com. |
El 500 es un error del servidor y no de la solicitud: repetirla con otros datos no lo resuelve, así que escribe a soporte.
Errores del servidor
Un error del servidor (5xx) no se resuelve cambiando los datos de la solicitud. La respuesta trae traceIdentifier (ver ApiResponse): inclúyelo al escribir a soporte, porque identifica la petición en los registros de Fiscalapi. El campo message indica de qué lado está la causa:
| Estado | message | Qué hacer |
|---|---|---|
| 4xx | Sorry, it's not me, it's you. | Corrige la solicitud. |
| 5xx | Sorry, it's not you, it's me. | Reintenta o escribe a soporte con el traceIdentifier. |
| 500 (error inesperado) | Something went wrong on our end. | Escribe a soporte con el traceIdentifier. |
Conservan su propio message el rechazo del PAC al timbrar o cancelar, el 425 (Too Early) de Descargar paquete por ID y el 429 (Too Many Requests) del límite de solicitudes. Los errores del servidor responden así:
| Estado | Cuándo ocurre | message | details |
|---|---|---|---|
| 500 | Error inesperado. El detalle técnico queda solo en los registros de Fiscalapi, con el mismo traceIdentifier. | Something went wrong on our end. | Ocurrió un error inesperado en el servidor. Escríbenos a soporte@fiscalapi.com con el traceIdentifier de esta respuesta. |
| 500 | Un error con un texto propio, como el del dato protegido que Fiscalapi no puede descifrar (ver Certificados y llaves privadas). | Sorry, it's not you, it's me. | El texto propio del error. |
| 502 | Una operación que consulta a Stripe, el proveedor de pagos de Fiscalapi (compras y suscripción desde el Dashboard), cuando Stripe falla o no está disponible. | Sorry, it's not you, it's me. | No pudimos completar la operación con Stripe. Intenta de nuevo en unos minutos; si continúa, escríbenos a soporte@fiscalapi.com con el traceIdentifier de esta respuesta. |
| 502 | Crear solicitud de descarga, cuando el SAT no pudo crearla. | Sorry, it's not you, it's me. | El texto propio del error. |
| 503 | La base de datos de Fiscalapi no respondió a tiempo o no está disponible. Repite la solicitud más tarde. | Sorry, it's not you, it's me. | La base de datos no respondió a tiempo o no está disponible. Intenta de nuevo en unos minutos; si continúa, escríbenos a soporte@fiscalapi.com con el traceIdentifier de esta respuesta. |
| 503 | Enviar factura por correo, cuando el proveedor de correo no está disponible. | Sorry, it's not you, it's me. | El texto propio del error. |
Ejemplo (error inesperado):
{
"data": null,
"succeeded": false,
"message": "Something went wrong on our end.",
"details": "Ocurrió un error inesperado en el servidor. Escríbenos a soporte@fiscalapi.com con el traceIdentifier de esta respuesta.",
"httpStatusCode": 500,
"traceIdentifier": "5C1E0B7A92D44F3E8A6B1D07F3C29E41"
}
Resultado incierto del timbrado
Al timbrar, si el PAC no responde a tiempo o responde un error de su servidor sin un código de rechazo, el resultado es incierto: el CFDI pudo quedar timbrado. Fiscalapi responde el error inesperado (500) y conserva el timbre consumido y el folio de la factura para conciliarlos; no los devuelve.
No repitas la factura de inmediato, porque podrías timbrar dos veces la misma operación. Consulta tus facturas con Listar facturas y, si no aparece, escribe a soporte con el traceIdentifier de la respuesta. Un rechazo del PAC con su código sí es un rechazo: se reembolsa el timbre y la respuesta trae el mensaje del PAC.
Restricciones de los datos y concurrencia
Al escribir los datos, la base de datos de Fiscalapi también rechaza lo que la solicitud causó y que no detectó antes una validación del campo. Estas respuestas son errores del cliente y no traen falla de validación ni campo: el motivo va en details, en español.
| Estado | Cuándo ocurre | message | details |
|---|---|---|---|
| 400 | Ya existe un registro con un valor que debe ser único. | Sorry, it's not me, it's you. | Ya existe un registro con los mismos datos únicos. |
| 400 | Un registro relacionado no existe o depende del que se elimina, o un valor no cumple una regla de la base de datos. | Sorry, it's not me, it's you. | La operación no cumple una restricción de los datos: un registro relacionado no existe o depende de este, o un valor no es válido. |
| 400 | Falta un dato obligatorio. | Sorry, it's not me, it's you. | Falta un dato obligatorio. |
| 400 | Un texto es más largo que su máximo. | Sorry, it's not me, it's you. | Uno o más campos exceden la longitud máxima permitida. |
| 400 | Un valor tiene un formato que no se puede convertir (por ejemplo, una fecha). | Sorry, it's not me, it's you. | El formato de uno o más campos es incorrecto. |
| 400 | Un número es mayor que el máximo de su columna. | Sorry, it's not me, it's you. | Uno o más valores numéricos exceden el máximo permitido. |
| 409 | Otra petición modificó o eliminó el registro entre su lectura y su escritura. No se guarda nada. | Sorry, it's not me, it's you. | Otra petición modificó o eliminó el registro después de leerlo. Vuelve a consultarlo e inténtalo de nuevo. |
Ante un 409, vuelve a consultar el registro y repite la solicitud. Las personas conservan su propio 409 (ver Actualizar emisor). Cualquier otra falla de la base de datos responde el error inesperado (500).
Errores específicos
Las tablas completas de errores de nivel 2 están en estas páginas:
| Página | Qué cubre |
|---|---|
| Errores CFDI 4.0 | Facturación general, con códigos CFDI40xxx. |
| Errores Nómina 1.2 | Complemento de nómina, con códigos NOMxx. |
| Errores Carta Porte 3.1 | Complemento Carta Porte, con códigos CPxxx. |
| Errores Pagos 2.0 | Complemento de pagos, con códigos CRPxxxxx. |
| Errores Comercio Exterior 2.0 | Complemento de comercio exterior, con códigos CCExxx. |