Skip to content

Errores

La forma

Todos los errores del API son RFC 7807, con Content-Type: application/problem+json:

json
{
  "type": "https://api.factura.sv/errores/documento-invalido",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "El receptor de un Comprobante de Crédito Fiscal necesita NIT y NRC.",
  "errors": [
    "receptor.nit: es obligatorio para el tipo 03",
    "receptor.nrc: es obligatorio para el tipo 03"
  ]
}

Programa contra type. Es un identificador estable; el último segmento de la URL es el código del error. detail está escrito para mostrárselo a una persona y su redacción puede cambiar sin aviso.

errors aparece cuando hay varios problemas a la vez. Trae todos, no solo el primero: devolver uno obligaría a corregir de uno en uno y a descubrir el siguiente en el siguiente viaje.

javascript
const codigo = problema.type.split("/").pop();
switch (codigo) {
  case "falta-idempotency-key": /* bug tuyo, arréglalo */ break;
  case "configuracion-incompleta": /* avisa al contribuyente */ break;
  default: /* registra y muestra `detail` */
}

Qué hacer según el código HTTP

Qué significaQué hacer
400La petición está mal formada.Es un bug de tu integración. No reintentes.
401Credencial ausente, inválida o revocada.Revisa la API key. No reintentes.
403La credencial es válida pero le falta el permiso.Pide que le añadan el scope. No reintentes.
402El contribuyente se quedó sin DTE contratados, o su servicio está detenido.Muéstrale detail tal cual: tiene que entrar al panel. No reintentes.
404No existe, o no es de este contribuyente. No se distingue cuál.No reintentes.
409El estado actual no permite la operación.Depende del código; casi nunca se arregla reintentando lo mismo.
413El cuerpo es demasiado grande.Divide el lote, o reduce la imagen.
422Los datos no pasan la validación.Corrige lo que diga errors. No reintentes igual.
429Demasiadas peticiones, o cuenta bloqueada.Espera y reintenta con espera creciente.
500Fallo del servidor.Reintenta con espera exponencial.
503Falta una dependencia (catálogos sin sembrar, almacén caído).Reintenta más tarde; probablemente hay que avisar.

Reintentar automáticamente solo tiene sentido en 429, 500 y 503. Todo lo demás volverá a fallar igual, y en emisión gastarías el intento sin necesidad. Recuerda mantener la misma Idempotency-Key en el reintento.

Los que te van a pasar

falta-idempotency-key · 400

Emitiste sin la cabecera. → Idempotencia

saldo-dte-agotado · 402

El contribuyente agotó los DTE de su paquete. No es un fallo tuyo ni algo que se arregle reintentando: hasta que no contrate más, ninguna emisión va a pasar.

Lo que tu integración tiene que hacer es enseñarle el detail a quien esté delante de la pantalla, porque ahí dice qué hacer: entrar al panel y contratar. Un mensaje genérico de «error al facturar» deja al cajero llamando al soporte por algo que resuelve el propio contribuyente en dos minutos.

Las invalidaciones siguen pasando aunque el saldo esté agotado, hasta un pequeño margen: nadie debe quedarse sin poder anular un documento erróneo dentro de las 24 horas que da la ley.

suscripcion-bloqueada · 402

Hay una factura del servicio pendiente de pago. Contratar más DTE no lo soluciona; hay que regularizar el pago desde el panel.

suscripcion-suspendida · 402

El servicio está suspendido por decisión comercial. Solo lo reactiva el proveedor.

documento-invalido · 422

El más frecuente al empezar. errors dice exactamente qué falta. Las causas habituales:

  • Receptor incompleto en un CCF: le faltan nit, nrc, codActividad o la dirección.
  • Un código de catálogo que no existe. Ojo con el municipio: no es único por sí solo, se repite entre departamentos.
  • documentosRelacionados en un tipo que no los admite, o ausente en una nota.
  • Intentar ajustar con una nota un documento tipo 01 o 14: no transfieren crédito fiscal, así que no hay nada que ajustar. Solo se pueden ajustar 03, 05, 06, 07, 08, 09 y 11.

configuracion-incompleta · 409

Al contribuyente le falta el certificado de firma, las credenciales de Hacienda o los correlativos. No es un problema de tu integración: avisa a quien administre esa cuenta. Reintentar no va a servir hasta que lo carguen.

punto-venta-invalido · 422

Mandaste un codEstable o codPuntoVenta que no existe. Consulta GET /api/v1/dte/establecimientos.

documento-no-sellado · 409

Intentaste invalidar un documento que no está SELLADO. Un rechazado no existe para Hacienda: no hay nada que anular.

ya-invalidado · 409

Ese documento ya se invalidó. Es idempotente en la práctica: el resultado que querías ya está.

existencia-insuficiente · 409

Solo en /gestion/ventas. No hay inventario para lo que se intenta vender. Es un error de negocio, no un fallo: alguien tiene que decidir qué hacer.

demasiados-intentos / cuenta-bloqueada · 429

Limitador del login. Espera y reintenta con espera creciente.

Catálogo completo

Ordenado por código HTTP. El identificador es el último segmento de type.

400 — la petición está mal formada

CódigoCuándo
falta-idempotency-keyEmitir sin la cabecera obligatoria.
json-invalidoEl cuerpo no es JSON válido, o trae campos desconocidos.
cuerpo-vacioSe esperaba un cuerpo y no vino.
cuerpo-invalidoEl cuerpo no tiene la forma esperada.
datos-incompletosFaltan campos obligatorios de la petición.
fecha-invalidaUna fecha no viene como AAAA-MM-DD.
periodo-invalidoFaltan desde/hasta, o el rango está al revés.
rango-invalidohasta es anterior a desde.
espera-invalidaEl parámetro esperar no es una duración válida, o pasa de 20 s.

401 — no autenticado

CódigoCuándo
credencial-invalidaAPI key ausente, mal formada, inexistente o revocada; o contraseña incorrecta. No se distingue cuál, para no filtrar qué llaves existen.
enlace-invalidoEl enlace de recuperación de contraseña es inválido o venció.
totp-invalidoEl código TOTP no coincide, o el desafío del login venció o ya se usó.

403 — autenticado pero sin permiso

CódigoCuándo
sin-permisoA la credencial le falta el scope.
sesion-requeridaLa operación exige una sesión de persona; una API key no sirve.
reautenticacion-requeridaHace falta step-up: la contraseña otra vez, aunque la sesión siga viva. Si el segundo factor está activo, también el código.
totp-pendienteEl rol exige TOTP y todavía no está activo. Solo aplica a sesiones de persona (admin y operador), nunca a una API key.
solo-maestroSolo el usuario maestro del contribuyente puede hacerlo.
codigo-requerido / codigo-invalidoAcceso de soporte con código de autorización.

404 — no existe

CódigoCuándo
documento-no-encontradoEse código de generación no existe o no es de este contribuyente.
no-encontrado / no-encontradaGenérico para el resto de recursos.
catalogo-no-encontradoEse catálogo no existe.
clave-no-encontradaEsa API key no existe.
webhook-no-encontradoEse webhook no existe.
lote-no-encontradoEse lote no existe.
exportacion-no-encontradaEsa exportación no existe.
sin-logotipoEl contribuyente no tiene logotipo cargado.
no-configuradoFalta configurar algo que la operación necesita.

409 — el estado actual no lo permite

CódigoCuándo
configuracion-incompletaFalta certificado, credenciales de MH o correlativos.
emisor-no-configuradoEl contribuyente no tiene datos fiscales cargados.
documento-no-selladoSe intentó invalidar o retornar algo que no está sellado.
ya-invalidadoYa se invalidó.
retorno-vigenteHay un Evento de Retorno en camino o sellado; hay que invalidarlo antes de invalidar la factura.
correlativo-retrocedeSe intentó posicionar una serie hacia atrás. Serían dos documentos con el mismo número de control.
existencia-insuficienteNo hay inventario.
venta-no-anulableLa venta tiene un DTE con valor fiscal: hay que invalidarlo ante MH primero.
plazo-vencidoSe pasó el plazo legal de la operación.
duplicado, nit-duplicado, usuario-duplicado, operador-duplicado, nombre-repetidoYa existe algo con esa clave.
plantilla-en-usoLa plantilla está asignada. ?forzar=1 borra también las asignaciones.
rol-en-uso / rol-de-sistemaEl rol tiene usuarios, o es uno de los tres de sistema.
maestro-protegido / sin-maestro / ultimo-operadorProtecciones para no dejar una cuenta sin quien la administre.
exportacion-no-listaEl ZIP todavía se está armando.
sin-documentosEl período no tiene nada que exportar.
sin-cuenta-de-soporteEl contribuyente no tiene habilitado el acceso de soporte.

413 — demasiado grande

CódigoCuándo
cuerpo-grandeEl cuerpo pasa del máximo. Un DTE de 2000 ítems no llega a 1 MB.
logotipo-grandeLa imagen del logotipo pasa del máximo.

422 — los datos no son válidos

CódigoCuándo
documento-invalidoEl DTE no pasa las reglas de su tipo o el esquema de MH. errors trae todo.
datos-invalidosGenérico de validación.
datos-incompletosFaltan campos obligatorios.
punto-venta-invalidoEl establecimiento o el punto de venta no existen.
invalidacion-invalidaLos datos de la anulación no son válidos.
tipo-sin-retornoEse tipo de DTE no admite Evento de Retorno (un CCF se ajusta con Nota de Crédito).
retorno-excedeLa suma de retornos superaría el valor del documento original.
retorno-invalidoLos datos del retorno no son válidos.
certificado-invalido / contrasena-llave-incorrectaEl archivo no es un certificado válido, o la contraseña de la llave no abre.
ambiente-invalidoAmbiente distinto de 00 o 01.
nit-inmutableEl NIT no se cambia desde el panel: es la llave del login.
contrasena-debilLa contraseña no cumple el mínimo.
scopes-invalidosSe pidió un scope que no existe.
url-invalidaLa URL del webhook no sirve.
eventos-invalidosSe pidió un evento de webhook desconocido.
lote-vacio / lote-invalido / lote-excedidoProblemas con el lote.
contingencia-invalidaLos datos de la contingencia no son válidos.
responsable-incompleto / responsable-no-configuradoFalta el responsable de contingencias.
plantilla-invalida / plantilla-desconocida / diseno-desconocido / asignacion-invalidaProblemas con la plantilla del PDF.
imagen-invalidaEl logotipo no es una imagen que se pueda leer.
formato-desconocidoSe pidió un formato de salida que no existe.
no-se-pudo-dibujarEl PDF no se pudo generar con esa plantilla.
configuracion-invalidaLa configuración enviada no es coherente.

429 — demasiadas peticiones

CódigoCuándo
demasiados-intentosLimitador por IP en el login.
cuenta-bloqueadaBloqueo progresivo por fallos de contraseña.

500 y 503 — el problema es del servidor

CódigoCuándo
error-internoFallo no previsto. Reintenta con espera exponencial.
documento-corruptoEl documento guardado no se puede leer. Hay que reportarlo.
catalogos-sin-sembrarLa instalación no tiene los catálogos de MH cargados.
sin-almacenEl almacén de objetos no responde.
correo-no-entregadoEl proveedor de correo rechazó el envío (502).