Ir al contenido

FISCALISTO / API

Errores

Cada error dice qué pasó, qué campo corregir y cómo. Aquí está cada código que puede recibir.

Un error responde con un código HTTP 4xx o 5xx y siempre con el mismo cuerpo:

{
  "error": {
    "type": "invoice_error",
    "code": "invoice_rejected",
    "message": "El SAT no reconoce el nombre del cliente. Escríbalo exactamente como en su constancia de situación fiscal, en mayúsculas y sin «S.A. de C.V.» ni otro régimen de capital.",
    "param": "customer",
    "sat_code": "CFDI40145",
    "invoice": "inv_roVZuc6krJsw08oPyaiBiYX4fWH2pyEN1x",
    "doc_url": "https://fiscalisto.com/docs/api/errores#invoice_rejected",
    "request_id": "req_FfCT3zz9ktKinNLSGMqu"
  }
}
CampoQué es
typeLa familia del error. Su código decide qué hacer con este.
codeLa razón precisa, estable: no cambia entre versiones. Está en la lista de abajo.
messageQué pasó y cómo corregirlo, en español, para mostrarlo a una persona. Puede mejorar con el tiempo: no lo compare en su código.
paramEl campo que hay que corregir, con su ruta en el cuerpo (items.0.unit_price, customer.zip).
sat_codeEl código del SAT o del PAC cuando ellos lo rechazaron (CFDI40145).
doc_urlEsta página, en el código del error.
request_idEl id de la solicitud, el mismo del encabezado Request-Id. Búsquelo en Desarrolladores › Solicitudes o mándelo a soporte.

Un rechazo del SAT o del PAC trae además el id del comprobante rechazado en invoice (o retention en una constancia), para consultarlo.

Qué hacer con cada tipo

typeHTTPQué hacer
invalid_request_error400Corregir la solicitud: param y message dicen qué.
authentication_error401Revisar la llave.
balance_error402Comprar timbres y repetir con la misma Idempotency-Key.
permission_error403Usar una llave que pueda con ese emisor.
not_found_error404Revisar el id y el modo de la llave.
idempotency_error409request_in_progress: esperar y repetir. idempotency_key_reused: usar otra llave.
invoice_error422Corregir los datos del comprobante: el SAT, el PAC o la revisión de Fiscalisto no lo aceptan.
rate_limit_error429Esperar lo que dice Retry-After y repetir.
api_error500, 503Repetir con la misma Idempotency-Key, con espera creciente.

Nunca se cobra un error

Ningún error usa un timbre: ni las revisiones de Fiscalisto, ni los rechazos del SAT o del PAC. Una factura rechazada queda guardada con status: "rejected" y su error, y puede consultarla con su id.

Si la API no contesta

Un 500, un 503 o un corte de red: repita con la misma Idempotency-Key y espera creciente (los SDKs ya lo hacen). Para saber si es general, vea fiscalisto.com/estado: dice si el timbrado, la API y las listas del SAT funcionan, desde cuándo fallan y cómo funcionaron en los últimos 90 días, revisado cada 15 minutos. Para sus monitores, lo mismo en JSON con GET https://fiscalisto.com/estado.json, sin llave:

{
  "status": "operativo",
  "checked_at": "2026-10-24T18:45:00.000Z",
  "page": "https://fiscalisto.com/estado",
  "components": [
    { "id": "pac", "name": "Timbrado y cancelación", "status": "operativo", "since": null },
    { "id": "api", "name": "API", "status": "operativo", "since": null },
    { "id": "sat_lists", "name": "Listas del SAT (69-B y 69)", "status": "operativo", "since": null }
  ]
}

status es operativo, degradado o interrumpido; since, desde cuándo, mientras no sea operativo. Con ?history=1 trae también los últimos 90 días (days: day, status y minutes con fallas). Se actualiza cada minuto; no lo consulte más seguido. Para enterarse sin consultar: avisos por correo en Estado del servicio o el RSS https://fiscalisto.com/estado.rss, con cada incidente al empezar y al resolverse.

En inglés

Con el encabezado Accept-Language: en los errores llegan en inglés (y Content-Language: en). Los de validación dicen exactamente lo mismo que en español (unit_price: must be greater than or equal to 0.). Los demás dicen en inglés qué significa su code, y traen el mensaje original, más preciso, en message_es. Los datos no se traducen: los catálogos, nombres y campos del CFDI son los del SAT.

curl https://api.fiscalisto.com/v1/invoices/inv_nope \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Accept-Language: en"

En los SDKs, la opción language: "en" (language="en" en Python, 'language' => 'en' en PHP, WithLanguage("en") en Go, .language("en") en Java y Language = "en" en .NET).

Errores de validación

Antes de mandar al PAC, Fiscalisto revisa la factura completa con los catálogos y las reglas del SAT (por ejemplo, que el uso del CFDI corresponda al régimen del cliente o que los totales cuadren). Así casi todo error llega como parameter_invalid o invoice_invalid, con param, sin gastar tiempo ni timbre en el PAC. Un campo que no existe nunca se ignora en silencio: responde parameter_unknown, porque casi siempre es un nombre mal escrito.

Solicitud inválida

type: invalid_request_error.

parameter_missing

HTTP 400. Falta un campo obligatorio. param dice cuál.

parameter_invalid

HTTP 400. Un campo tiene un valor que no se acepta (formato, catálogo del SAT, rango). param dice cuál y message cómo corregirlo.

parameter_unknown

HTTP 400. Mandó un campo o un parámetro de la URL que no existe (casi siempre un nombre mal escrito, como legalName en vez de legal_name, o ?statuss= en vez de ?status=). Nunca se ignora en silencio.

body_too_large

HTTP 413. El cuerpo pasa de 10 MB. Divida el trabajo en varios lotes.

data_request_completed

HTTP 400. El cliente ya mandó sus datos con esa liga: una solicitud completada no se cancela.

invalid_json

HTTP 400. El cuerpo no es un objeto JSON válido.

unsupported_content_type

HTTP 400. Mande el cuerpo con Content-Type: application/json.

method_not_allowed

HTTP 405. La ruta existe pero no con ese método (por ejemplo, PUT: la API usa POST para actualizar).

browser_not_supported

HTTP 400. La API se llama desde su servidor, nunca desde el navegador: la llave secreta quedaría expuesta.

livemode_mismatch

HTTP 400. El objeto es del otro modo: una llave fk_test_ solo ve lo de pruebas y una fk_live_ lo de producción.

issuer_required

HTTP 400. La cuenta tiene varios emisores y la solicitud no dice cuál: mande issuer (iss_…).

issuer_exists

HTTP 400. Ese RFC ya es un emisor de la cuenta en este modo.

issuer_archived

HTTP 400. El emisor está archivado: ya no timbra. Sus comprobantes se pueden consultar y cancelar.

certificate_invalid

HTTP 400. El CSD no sirve: no es un certificado de sello (es una e.firma), está vencido, el .key no corresponde o la contraseña no abre la llave.

certificate_required

HTTP 400. Suba primero el CSD del emisor; después firme el contrato con su e.firma.

efirma_invalid

HTTP 400. La e.firma no sirve: no es una e.firma (es un CSD), es de otro RFC, está vencida o la contraseña no abre la llave.

efirma_required

HTTP 400. Para pedirle al SAT las facturas de un emisor en producción, guarde antes su e.firma: POST /v1/issuers/{id}/efirma con keep_for_downloads: true. También si la guardada venció.

test_mode_only

HTTP 400. Esto solo existe en pruebas (como reiniciar los datos de prueba): use su llave fk_test_.

sat_request_rejected

HTTP 400. El SAT rechazó la solicitud de descarga. El mensaje trae su motivo, por ejemplo que ya se pidió el mismo periodo con los mismos filtros demasiadas veces (el SAT pone un límite de por vida).

ticket_invalid

HTTP 400. El ticket no se pudo registrar: el folio trae caracteres no válidos, la fecha de venta está en el futuro o es de hace más de un año, el producto ya no está en el catálogo… El mensaje dice cuál.

ticket_folio_taken

HTTP 400. Ese folio ya está registrado para el emisor con otro total o con otra propina (409). Con el mismo total se contesta el ticket que ya existe.

ticket_not_pending

HTTP 400. El ticket ya se facturó o entró en una factura global: no se puede cancelar.

recurring_invalid

HTTP 400. La factura recurrente no se pudo guardar: el día, la hora, la zona o la factura no son válidos. El mensaje dice cuál.

recurring_limit

HTTP 400. El emisor ya tiene el máximo de facturas recurrentes activas (25 en pruebas, 5,000 en producción). Pause o borre las que ya no use.

recurring_paused

HTTP 400. La factura recurrente está en pausa: reanúdela con active: true para timbrarla.

recurring_not_due

HTTP 400. Aún no toca timbrar la factura recurrente (409): su next_invoice_on es después de hoy. Para una factura antes de tiempo, use POST /v1/invoices.

invoice_not_markable

HTTP 400. Solo una factura de ingreso PUE vigente se marca pagada o por cobrar; una PPD se paga con su complemento de pago (type P).

bank_transaction_invalid

HTTP 400. El depósito no se puede conciliar, clasificar o reabrir así (ya está conciliado, las facturas son de otro cliente o una está cancelada…). El mensaje dice por qué.

diot_empty

HTTP 400. El mes no tiene pagos a proveedores: esa DIOT se presenta sin operaciones desde el portal del SAT.

store_connection_failed

HTTP 400. La tienda no aceptó la conexión o no respondió como se esperaba (llaves equivocadas, permisos read_orders/write_orders que faltan, una tienda que no vende en pesos). El mensaje dice qué contestó.

store_platform_unavailable

HTTP 400. Esa plataforma aún no está disponible en Fiscalisto.

sandbox_invalid

HTTP 400. No se pudo crear el entorno de prueba: falta su nombre o la cuenta ya tiene 25 (borre uno que ya no use).

api_version_invalid

HTTP 400. No existe esa versión de la API (en Fiscalisto-Version o api_version). El mensaje dice cuáles hay; vea Versiones.

expand_invalid

HTTP 400. Un campo de expand[] no existe en la respuesta, no es el id de otro objeto, o se pidieron demasiados (hasta 10 campos, 4 niveles). Vea Expandir objetos.

test_clock_unsupported

HTTP 400. Los relojes de prueba son de emisores de prueba: use su llave fk_test_ y un emisor de pruebas.

test_clock_exists

HTTP 409. El emisor ya tiene un reloj de prueba: adelántelo, o bórrelo para volver a la hora real.

test_clock_invalid

HTTP 400. frozen_time no sirve: no es una fecha y hora ISO 8601, es anterior a la hora del reloj (solo avanza) o va más de dos años adelante de la hora real.

test_clock_advancing

HTTP 409. El reloj se está adelantando en otra solicitud (409, con Retry-After). Espere a test_clock.ready y repita.

store_already_connected

HTTP 400. Esa tienda ya está conectada a este emisor.

store_not_authorized

HTTP 400. El vendedor aún no autoriza la conexión en authorize_url.

store_disconnected

HTTP 400. La tienda se desconectó: conéctela otra vez con POST /v1/store_connections.

quote_invalid

HTTP 400. La cotización no se pudo guardar o ya no cambia (aceptada, rechazada o facturada), o no se puede mandar así. El mensaje dice por qué.

quote_not_draft

HTTP 400. Solo se borra una cotización que nunca se envió.

quote_not_invoiceable

HTTP 400. La cotización se rechazó o venció: no se factura. Si venció, cámbiele valid_until (es una versión nueva).

quote_customer_missing

HTTP 400. La cotización no tiene los datos fiscales del cliente: agrégueselos con POST /v1/quotes/{id} (customer) o mándela con auto_invoice para que los dé al aceptarla.

idempotency_key_missing

HTTP 400. Lo que timbra exige el encabezado Idempotency-Key (8 a 255 caracteres, uno nuevo por comprobante). Así un reintento nunca timbra dos veces.

idempotency_key_invalid

HTTP 400. Idempotency-Key es de 1 a 255 caracteres ASCII, sin acentos ni ñ: el id de su pedido o un UUID.

invoice_not_stamped

HTTP 400. La acción es para facturas timbradas (enviar, cancelar, sustituir).

substitution_unsupported

HTTP 400. Los complementos de pago y las notas de crédito no se sustituyen: se cancelan y se emite otro.

retention_not_stamped

HTTP 400. La acción es para constancias timbradas.

customer_exists

HTTP 400. Ya hay un cliente con ese RFC en el catálogo del emisor (o un producto con ese SKU).

branch_exists

HTTP 400. El emisor ya tiene una sucursal con ese código postal (cada una lleva el suyo); el mensaje dice cuál. Si está archivada, restáurela con archived: false.

branch_has_invoices

HTTP 400. La sucursal ya facturó, así que no se borra: archívela con archived: true y sus facturas la siguen nombrando.

inventory_refused

HTTP 400. Inventario no lo permite: el mensaje dice por qué (un lote que no es de ese producto, otro ajuste del mismo almacén en curso).

email_failed

HTTP 400. No se pudo mandar el correo; el comprobante sí está timbrado.

endpoint_exists

HTTP 400. Ya hay un webhook con esa dirección en este modo; el mensaje dice cuál. Cámbielo en vez de crear otro.

endpoint_limit

HTTP 400. La cuenta llegó al máximo de webhooks en este modo.

Autenticación

type: authentication_error.

missing_api_key

HTTP 401. Falta el encabezado Authorization: Bearer fk_test_… o fk_live_….

invalid_api_key

HTTP 401. La llave no existe, se revocó o expiró. Cree otra en Desarrolladores › Llaves.

Permisos

type: permission_error.

key_restricted

HTTP 403. La llave está limitada a algunos emisores y la solicitud toca otro (o crea uno nuevo, o usa algo de toda la cuenta como webhooks).

key_in_sandbox

HTTP 403. La llave es de un entorno de prueba y la solicitud es de toda la cuenta (como crear o borrar entornos): use una llave de pruebas de la cuenta.

issuer_not_allowed

HTTP 403. La llave no puede usar ese emisor.

key_read_only

HTTP 403. La llave es de solo lectura: puede hacer GET, validar RFC, revisar listas del SAT y calcular recibos de nómina, pero nada que timbre, cancele, envíe o cambie datos.

No encontrado

type: not_found_error.

route_not_found

HTTP 404. No existe esa ruta. Revise la dirección y la versión (/v1).

issuer_missing

HTTP 404. No existe ese emisor en la cuenta (o es del otro modo).

test_clock_missing

HTTP 404. El emisor no tiene reloj de prueba: créelo con POST /v1/issuers/{id}/test_clock.

resource_missing

HTTP 404. No existe un objeto con ese id (o es de otro emisor o del otro modo).

Idempotencia

type: idempotency_error.

idempotency_key_reused

HTTP 409. Esa Idempotency-Key ya se usó en las últimas 24 horas con otra solicitud (otra ruta u otro cuerpo). Use una nueva para cada operación distinta.

request_in_progress

HTTP 409. Otra solicitud con la misma Idempotency-Key sigue en proceso, o otra solicitud está cambiando el mismo objeto (dos actualizaciones del mismo cliente a la vez esperan su turno hasta 15 segundos) (409, con Retry-After). Repítala en un momento con la misma llave: contestará lo mismo.

Comprobantes

type: invoice_error.

invoice_invalid

HTTP 422. La factura no cumple una regla del SAT que Fiscalisto revisa antes de mandarla al PAC (uso contra régimen, totales, complementos…). No se usó ningún timbre.

invoice_rejected

HTTP 422. El PAC o el SAT no la aceptaron. sat_code trae su código (CFDI40xxx) y message qué corregir. La factura queda como rejected; no se usó ningún timbre.

cancellation_failed

HTTP 422. El SAT no aceptó la solicitud de cancelación; message dice por qué.

payroll_invalid

HTTP 422. El recibo de nómina no se puede calcular o timbrar con esos datos (periodo, días, registro patronal del emisor…).

retention_invalid

HTTP 422. La constancia de retenciones no cumple una regla del SAT. No se usó ningún timbre.

retention_rejected

HTTP 422. El PAC o el SAT no aceptaron la constancia; sat_code trae su código.

batch_invalid

HTTP 422. Una factura del lote no pasa la revisión; param dice cuál (invoices.3.items.0.unit_price). Ninguna del lote se timbró.

Timbres

type: balance_error.

insufficient_balance

HTTP 402. La cuenta no tiene timbres de producción: para timbrar, revisar RFC en las listas, consultar constancias o pedir descargas al SAT. Compre un paquete en Desarrolladores › Timbres. En pruebas nunca pasa. Para enterarse antes, escuche balance.low o active la recarga automática.

Límites

type: rate_limit_error.

issuer_creation_limit

HTTP 429. Se crearon 500 emisores en 24 horas. Escríbanos si necesita más.

sat_refresh_too_soon

HTTP 429. Las declaraciones de ese emisor se consultaron en el SAT hace menos de 10 minutos (cada consulta entra al SAT con su e.firma). Retry-After dice cuántos segundos faltan; lo que ya trajo está en GET /v1/sat_declarations.

stamp_rate_limit

HTTP 429. Demasiados timbres seguidos del mismo emisor. Espere lo que dice Retry-After; para muchas facturas use POST /v1/invoice_batches.

daily_limit

HTTP 429. Llegó al tope del día de algo que no se paga con timbres: comprobantes en pruebas (1,000), RFC revisados en las listas del SAT o constancias consultadas. Retry-After dice cuántos segundos faltan para la medianoche de la Ciudad de México.

rate_limit

HTTP 429. Demasiadas solicitudes con la llave. Espere lo que dice Retry-After y reintente.

Errores de Fiscalisto

type: api_error.

sat_unavailable

HTTP 502. El SAT no contestó o no dejó entrar con la e.firma del emisor. El mensaje trae lo que dijo; no se usó ningún timbre. Reintente en 10 minutos.

catalog_unavailable

HTTP 503. El catálogo del SAT no respondió (503). Reintente en unos segundos.

internal_error

HTTP 500. Algo falló de nuestro lado. Repita la solicitud con la misma Idempotency-Key: nunca se timbra dos veces. Si sigue, escríbanos con el request_id.

En esta página

Qué hacer con cada tipoSi la API no contestaEn inglésErrores de validaciónSolicitud inválidaparameter_missingparameter_invalidparameter_unknownbody_too_largedata_request_completedinvalid_jsonunsupported_content_typemethod_not_allowedbrowser_not_supportedlivemode_mismatchissuer_requiredissuer_existsissuer_archivedcertificate_invalidcertificate_requiredefirma_invalidefirma_requiredtest_mode_onlysat_request_rejectedticket_invalidticket_folio_takenticket_not_pendingrecurring_invalidrecurring_limitrecurring_pausedrecurring_not_dueinvoice_not_markablebank_transaction_invaliddiot_emptystore_connection_failedstore_platform_unavailablesandbox_invalidapi_version_invalidexpand_invalidtest_clock_unsupportedtest_clock_existstest_clock_invalidtest_clock_advancingstore_already_connectedstore_not_authorizedstore_disconnectedquote_invalidquote_not_draftquote_not_invoiceablequote_customer_missingidempotency_key_missingidempotency_key_invalidinvoice_not_stampedsubstitution_unsupportedretention_not_stampedcustomer_existsbranch_existsbranch_has_invoicesinventory_refusedemail_failedendpoint_existsendpoint_limitAutenticaciónmissing_api_keyinvalid_api_keyPermisoskey_restrictedkey_in_sandboxissuer_not_allowedkey_read_onlyNo encontradoroute_not_foundissuer_missingtest_clock_missingresource_missingIdempotenciaidempotency_key_reusedrequest_in_progressComprobantesinvoice_invalidinvoice_rejectedcancellation_failedpayroll_invalidretention_invalidretention_rejectedbatch_invalidTimbresinsufficient_balanceLímitesissuer_creation_limitsat_refresh_too_soonstamp_rate_limitdaily_limitrate_limitErrores de Fiscalistosat_unavailablecatalog_unavailableinternal_error