Saltar al contenido principal

Códigos MH

Cuando el MH rechaza o anota un documento, devuelve códigos y observaciones que el API te expone en dte_state, codigo_msg, y observaciones. Esta página documenta los más frecuentes.

Estados del documento (dte_state)

EstadoSignificadoAcción
"" (vacío)Todo bien — MH aceptó con sello.Ninguna.
"PROCESADO"MH recibió y procesó exitosamente.Ninguna.
"RECHAZADO"MH rechazó el documento. No se generó sello.Corregir datos y reintentar con mismo external_ref.
"OBSERVADO"MH aceptó con observaciones. El documento es válido pero tiene advertencias.Revisar observaciones — informativo, no requiere acción obligatoria.

Cuando rejected: true, dte_state es "RECHAZADO" (u ocasionalmente "OBSERVADO" si el MH lo trató como rechazo).

Códigos de mensaje (codigo_msg)

El MH devuelve un código numérico breve (típicamente 2-3 dígitos) que identifica el tipo de error.

CódigoCategoríaDescripción
001ProcesoDocumento aceptado.
002ProcesoDocumento procesado con observaciones.
004DatosCódigo de generación ya ha sido procesado.
005AutorizaciónEmisor no autorizado.
006FirmaFirma digital inválida o vencida.
089ValidaciónCódigo de actividad económica inválido.
092ValidaciónTipo de documento del receptor inválido.
094ValidaciónNúmero de documento del receptor inválido.
095ValidaciónNRC del receptor inválido o inexistente.
096SchemaError al construir schema / JSON no cumple formato requerido. Suele indicar campo faltante o tipo incorrecto en el payload.
097ValidaciónFecha de emisión inválida.
098ValidaciónMonto total no coincide con suma de líneas.
099ValidaciónRetención calculada no coincide con normativa.
El código 096 es el más común

Indica que el JSON generado no cumple el esquema JSON Schema del MH. El mensaje en observaciones te dice qué campo falla. Ejemplos reales:

  • "Campo #/receptor/correo no cumple el formato requerido" → email del cliente inválido
  • "El valor del campo #/resumen/totalNoGravado debe ser tipo numero" → dato numérico mal tipado
  • "Campo #/receptor/nrc es requerido" → falta NRC en CCF

Observaciones frecuentes

observaciones es un array de strings. Cada string es un mensaje independiente del MH — puede venir uno solo o varios simultáneos. Muestra todos al usuario final; no filtres.

Categoría: Receptor (cliente)

"Campo #/receptor/correo no cumple el formato requerido"

Email del cliente malformado. Valida con regex ^[\w\.-]+@[\w\.-]+\.\w+$ antes de enviar, o pide al usuario que lo verifique.

"Campo #/receptor/nrc no cumple el formato requerido"

NRC debe ser un string numérico de 2-8 dígitos. Sin guiones.

"El valor del campo #/receptor/codActividad no está en el catálogo"

El activity_code no existe en el catálogo CAT-019 del MH. Consulta Catálogos MH para buscar el correcto.

"Combinación departamento/municipio inválida"

El department + municipality no corresponde a un municipio real. Ver el catálogo vivo /catalogs/departments.

Categoría: Montos

"El valor del campo #/resumen/totalNoGravado debe ser tipo numero"

Un monto que debería ser numérico viene como string u otro tipo. Caso poco común — si aparece, reporta a Ocote con el external_ref.

"Suma de líneas no coincide con total declarado"

Error de cálculo interno; raro pero posible. Reporta a Ocote con el external_ref.

Categoría: Emisor

"Firma digital vencida"

El certificado del emisor caducó. No es un error del cliente API — Ocote debe actualizar el firmador en la configuración de la empresa. Contacta a Ocote.

"Emisor no autorizado"

La empresa configurada no está habilitada para emitir el tipo de DTE solicitado. Contacta a Ocote.

Cómo manejar rechazos en tu integración

r = requests.post(".../invoice", json=payload, headers=h)
data = r.json()

if data["rejected"]:
# 1. Guardar en log el codigo_msg y observaciones para diagnostico
logger.error(f"MH rechazo: {data['codigo_msg']} - {data['dte_state']}")
logger.error(f"Observaciones: {data['observaciones']}")

# 2. Mostrar al usuario las observaciones tal cual (estan en espanol)
show_to_user("\n".join(data["observaciones"]))

# 3. NO reintentar automaticamente - el usuario debe corregir datos
return
  • Guarda siempre codigo_msg y observaciones en tu log, aunque el usuario resuelva en vivo. Es información valiosa para detectar patrones.
  • Muestra observaciones literal al usuario — los mensajes están en español y son relativamente legibles. Mejor que "error genérico".
  • No reintentes el rechazo en un bucle. A diferencia del timeout o 429, rechazo = datos malos = requiere acción humana.

Cuando el código no es conocido

Si recibes un codigo_msg que no está en esta tabla, revisa observaciones — ahí viene la descripción humana del error. El código numérico es secundario; la observación es el mensaje que realmente describe el problema. El MH periódicamente agrega códigos nuevos; este listado cubre los que hemos visto con frecuencia pero no es exhaustivo.

Ver también