Saltar al contenido principal

⚠️ Guía: Errores Comunes y Soluciones

📋 Introducción​

Esta guía enumera los errores más frecuentes al trabajar con la API MATIAS de facturación electrónica y cómo solucionarlos. Los ejemplos están basados en estructuras reales del API.

🔐
Autenticación
Tokens, credenciales, permisos
🧮
Cálculos
Totales, impuestos, descuentos
👥
Clientes
NIT, datos obligatorios
📝
Estructura JSON
Validación, campos requeridos

🔐 Errores de Autenticación​

❌ "Unauthorized" / "invalid_token"​

⚠️ Error Común: Este es uno de los errores más frecuentes. Generalmente el token ha expirado.

Respuesta del API:

{
"success": false,
"message": "Unauthorized - Token inválido o expirado"
}

HTTP Status: 401 - Unauthorized

Causas posibles:

  1. Token OAuth2 ha expirado (duración: 90 días máximo)
  2. Token no incluido en header Authorization
  3. Token no emitido: si el login falló, POST /auth/login responde 404 "Credenciales inválidas." y no entrega token
  4. Token malformado o corrupto
  5. Token revocado manualmente

Solución:

# 1. Obtener nuevo token
curl -X POST "{{url}}/auth/login" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"email": "tu-email@empresa.com",
"password": "tu-contraseña",
"remember_me": 0
}'

# 2. Respuesta con nuevo token
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjM...",
"user": {
"id": 1,
"email": "tu-email@empresa.com"
},
"expires_at": "2026-05-06 14:30:00",
"success": true
}

# 3. Usar en requests posteriores
curl -X POST "{{url}}/invoice" \
-H "Authorization: Bearer YOUR_NEW_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{...}'
💡 Pro tip

Novedad v3.0.0: Puedes crear Personal Access Tokens con duración configurable (de 1 a 365 días; 90 por defecto) para evitar estar renovando constantemente. Ver guía de PAT


📝 Errores de Estructura JSON​

❌ "Invalid JSON" / "Malformed request"​

Respuesta del API:

{
"success": false,
"message": "Invalid or malformed JSON"
}

HTTP Status: 400 - Bad Request

Causa común - JSON inválido:

Ejemplo de JSON malformado (falta cierre de llave):

{
"resolution_number": "18764074347312",
"prefix": "LZT",
"document_number": "2002"
}

Solución:

{
"resolution_number": "18764074347312",
"prefix": "LZT",
"document_number": "2002"
}

❌ "Campos requeridos faltantes"​

Respuesta del API:

{
"success": false,
"message": "Required field missing: lines"
}

HTTP Status: 400 - Bad Request

📋 Campos obligatorios:

CampoTipoDescripciónEjemplo
resolution_numberstring📜 Resolución DIAN de facturación"18764074347312"
prefixstring🏷️ Prefijo registrado"FEV", "FVD"
document_numberstring🔢 Número secuencial"2002"
type_document_idint📄 Tipo de documento7 (Factura)
operation_type_idint⚙️ Tipo de operación1 (Estándar)
customerobject👤 Datos del cliente/comprador{...}
linesarray📦 Ítems facturados[{...}]
legal_monetary_totalsobject💰 Totales finales{...}
paymentsarray💳 Información de pago[{...}]
⚠️ Importante

Verifica que el JSON incluya todos estos campos con valores válidos antes de enviar la solicitud.


🆔 Errores de Validación de NIT​

❌ "NIT con dígito verificador inválido"​

Respuesta del API:

{
"success": false,
"message": "El documento (cliente.dni) con numero 8001234567-8, no es valido"
}

HTTP Status: 422 - Unprocessable Entity

Ejemplo: NIT 8001234567-8 es inválido

🧮 Algoritmo Colombiano Correcto:

Posición: 1 2 3 4 5 6 7 8 9
Dígito: 8 0 0 1 2 3 4 5 6
Peso: 3 7 13 17 19 23 29 37 41

8×3 + 0×7 + 0×13 + 1×17 + 2×19 + 3×23 + 4×29 + 5×37 + 6×41
= 24 + 0 + 0 + 17 + 38 + 69 + 116 + 185 + 246
= 695

695 ÷ 11 = 63 resto 2
Dígito verificador = 11 - 2 = 9

✓ NIT correcto: 800123456-9

💡 Solución:

🔍 NITValidator
Herramientas Interactivas

🧮 Cálculo Manual
Usa el algoritmo anterior


🧮 Errores de Cálculo de Totales​

❌ "Total no coincide"​

❌ Error Crítico: Uno de los errores más comunes al crear facturas. Revisa los cálculos cuidadosamente.

Respuesta del API:

{
"error": true,
"errors": [
{
"field": "legal_monetary_totals",
"message": "Total no coincide con suma de líneas"
}
]
}

Ejemplo incorrecto:

{
"lines": [
{
"invoiced_quantity": "2",
"price_amount": "100.00",
"line_extension_amount": "200.00",
"tax_totals": [
{
"tax_id": "1",
"tax_amount": 38.00,
"taxable_amount": 200.00,
"percent": 19
}
]
}
],
"legal_monetary_totals": {
"line_extension_amount": "200.00",
"tax_exclusive_amount": "200.00",
"tax_inclusive_amount": "237.00",
"payable_amount": 237.00
}
}

Respuesta del API:

{
"success": false,
"message": "La validación de tax_inclusive_amount es incorrecta. Se esperaba 238.00, se recibió 237.00"
}

Corrección:

{
"legal_monetary_totals": {
"line_extension_amount": "200.00",
"tax_exclusive_amount": "200.00",
"tax_inclusive_amount": "238.00",
"payable_amount": 238.00
}
}

🎯 Fórmula Correcta:

tax_inclusive_amount = tax_exclusive_amount + SUMA(tax_totals[*].tax_amount)
payable_amount = tax_inclusive_amount

❌ "Impuesto calculado incorrectamente"​

Respuesta del API:

{
"error": true,
"errors": [
{
"field": "lines[0].tax_totals",
"message": "tax_amount no coincide con cálculo esperado"
}
]
}

Ejemplo incorrecto:

{
"lines": [
{
"line_extension_amount": "100.00",
"tax_totals": [
{
"tax_id": "1",
"tax_amount": 20.00, // ❌ INCORRECTO: 100 × 0.19 = 19
"taxable_amount": 100.00,
"percent": 19
}
]
}
]
}

Corrección:

{
"tax_totals": [
{
"tax_id": "1",
"tax_amount": 19.00,
"taxable_amount": 100.00,
"percent": 19
}
]
}
📊 Cálculo Correcto

100 × 0.19 = 19.00

🎯 Fórmula:

tax_amount = taxable_amount × (percent / 100)

❌ "Descuento excede el monto"​

Respuesta del API:

{
"success": false,
"message": "Allowance/Charge amount cannot exceed line base amount"
}

HTTP Status: 422 - Unprocessable Entity

Ejemplo incorrecto:

{
"lines": [
{
"price_amount": "100.00",
"allowance_charges": [
{
"amount": "150.00",
"base_amount": "100.00",
"charge_indicator": false
}
]
}
]
}

Corrección:

{
"allowance_charges": [
{
"amount": "50.00",
"base_amount": "100.00",
"charge_indicator": false
}
]
}
✅ Validación

El monto debe ser ≤ al monto base (50 ≤ 100) ✓


👥 Errores de Validación de Cliente​

❌ "Cliente no válido" / "Invalid party"​

Respuesta del API:

{
"error": true,
"errors": [
{
"field": "customer",
"message": "Datos de cliente incompletos"
}
]
}

📋 Campos requeridos del cliente:

CampoObligatorioEjemploDescripción
country_id✅ Sí"45"🌎 País (45 = Colombia)
city_id✅ Sí"76"🏙️ Ciudad (76 = Cali)
identity_document_id✅ Sí"2"🆔 Tipo documento (2 = NIT)
type_organization_id✅ Sí2🏢 Tipo organización
tax_regime_id✅ Sí1📊 Régimen tributario
company_name✅ Sí"CLIENTE LTDA"🏷️ Razón social
dni✅ Sí"8001234567"🔢 NIT sin dígito
email⚪ No"cliente@example.com"📧 Email contacto
mobile⚪ No"3001234567"📱 Teléfono móvil
address⚪ No"Calle 15 #8-30"📍 Dirección física

Ejemplo correcto:

{
"country_id": "45",
"city_id": "76",
"identity_document_id": "2",
"type_organization_id": 2,
"tax_regime_id": 1,
"tax_level_id": 5,
"company_name": "CLIENTE EMPRESA LTDA",
"dni": "8001234567",
"email": "compras@cliente.com",
"address": "Calle 15 #8-30",
"postal_code": "050001"
}

🔄 Errores de Factura Duplicada​

❌ "Documento duplicado"​

⚠️ Atención: Intentas crear un documento con un número que ya existe en el sistema.

Respuesta del API:

{
"message": "El documento (Factura electrónica) con numero LZT2002 ya se encuentra validado.",
"data": {
"uuid": "dde72910-eb42-11ef-9b27-f02f74cac485",
"document_number": "LZT2002",
"XmlDocumentKey": "cf9864294501e8a9578235dd2ab3c4fd...",
"is_valid": 1
},
"success": false
}

HTTP Status: 400 - Bad Request

Causa: El mismo prefix + document_number ya fue validado por la DIAN. En data llega el registro del envío existente.

💡 Soluciones:

✅ Opción 1: Incrementar número secuencial
Actual: LZT-2002 ❌ Ya existe
Nuevo: LZT-2003 ✓ Use este
✅ Opción 2: Usar diferente prefijo
Actual: LZT-2002 ❌ Ya existe
Nuevo: LZX-2002 ✓ Prefijo diferente

Solución - Opción 3: Consultar documento anterior

# Estado del documento (validación y QR)
curl -X GET "{{url}}/status?prefix=LZT&number=LZT2002" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Accept: application/json"

# O búsqueda en el listado de documentos
curl -X GET "{{url}}/documents?prefix=LZT&number=LZT2002" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Accept: application/json"
📜 IMPORTANTE

Los prefijos deben estar registrados previamente en tu resolución de facturación ante la DIAN.


🚦 Errores de Transmisión Concurrente, Validación Pendiente y Posible Envío​

Regla de oro

Ninguno de estos casos se resuelve emitiendo el documento con otro número. Consulta primero el estado del documento con GET /documents/{uuid} o GET /status?prefix=...&number=....

❌ DOCUMENT_IN_TRANSMISSION — el número ya se está transmitiendo​

HTTP Status: 409 - Conflict

{
"code": "DOCUMENT_IN_TRANSMISSION",
"message": "El documento LZT2002 ya se está transmitiendo a la DIAN en otra solicitud; consulte su estado antes de enviarlo de nuevo.",
"data": {
"document_number": "LZT2002"
},
"success": false
}

Causa: otra solicitud (un reintento, un doble clic o un lote) está transmitiendo ese mismo número a la DIAN.

Solución: no envíes el mismo documento en paralelo. Espera unos segundos y consulta su estado antes de reenviarlo.

❌ DOCUMENT_IN_VALIDATION — la DIAN aún valida el envío anterior​

HTTP Status: 409 - Conflict (solo en producción)

{
"code": "DOCUMENT_IN_VALIDATION",
"message": "La DIAN aún está validando el documento LZT2002 (CUFE/CUDE cf9864294501e8a9...). No se transmitió de nuevo: consulte su estado en unos minutos antes de reenviarlo.",
"data": {
"uuid": "dde72910-eb42-11ef-9b27-f02f74cac485",
"document_number": "LZT2002",
"document_key": "cf9864294501e8a9..."
},
"success": false
}

Causa: el envío anterior de ese número quedó en StatusCode 98 y la DIAN sigue validándolo.

Solución: espera unos minutos y consulta el estado con POST /status/document/{trackId} usando data.document_key.

❌ DIAN_STATUS_UNAVAILABLE — no se pudo confirmar el envío anterior​

HTTP Status: 503 - Service Unavailable (solo en producción)

{
"success": false,
"code": "DIAN_STATUS_UNAVAILABLE",
"message": "No se pudo confirmar en la DIAN el estado del envío anterior del documento LZT2002 (CUFE/CUDE cf9864294501e8a9...). No se transmitió de nuevo para no duplicarlo: intente en unos minutos.",
"data": {
"uuid": "dde72910-eb42-11ef-9b27-f02f74cac485",
"document_number": "LZT2002",
"document_key": "cf9864294501e8a9..."
}
}

Causa: no es una caída general de la DIAN: la API no pudo confirmar el estado del envío anterior de ese número y, para no duplicarlo, no transmitió el documento.

Solución: reintenta en unos minutos con el mismo número.

❌ DOCUMENT_POSSIBLY_SENT — posible envío sin respuesta definitiva​

HTTP Status: normalmente 500 - Internal Server Error

{
"success": false,
"message": "No se obtuvo una respuesta definitiva para el documento LZT2002 y es posible que la DIAN lo haya recibido. No lo emita de nuevo: consulte su estado con el uuid del envío antes de cualquier reintento. Detalle: Error interno del servidor. ...",
"reference": "3b0c6f5e-8d2a-4c7e-9f1b-2a6d5e4c3b21",
"code": "DOCUMENT_POSSIBLY_SENT",
"data": {
"uuid": "dde72910-eb42-11ef-9b27-f02f74cac485",
"document_number": "LZT2002"
}
}

Causa: el error (timeout, respuesta inesperada o fallo al guardar) ocurrió después de transmitir el documento a la DIAN. El consecutivo se conserva.

Solución: no reemitas. Consulta GET /documents/{uuid} con data.uuid (o GET /status) y actúa según su estado. Si reportas el caso a soporte, incluye reference.

❌ "El uuid proporcionado ya se usó en otro documento de la empresa"​

HTTP Status: 409 - Conflict

{
"success": false,
"message": "El uuid proporcionado ya se usó en otro documento de la empresa. No se emitió de nuevo: consulte ese documento o envíe un uuid nuevo."
}

Causa: el uuid anti-duplicados que enviaste ya pertenece a otro documento de la empresa. No se transmitió nada.

Solución: consulta ese documento con GET /documents/{uuid} o envía un uuid nuevo si se trata de otro documento.

⚠️ Avisos de regla 90: ALREADY_AUTHORIZED_* / ALREADY_PROCESSED_NOT_CONFIRMED​

En producción, cuando la DIAN responde "documento procesado anteriormente" (regla 90), la API concilia el número con la DIAN y lo informa en warnings:

codeSignificadoAcción
ALREADY_AUTHORIZED_RECOVEREDLa DIAN ya había autorizado ese número con el mismo contenido: se devuelve el documento autorizado.Ninguna: el documento es válido.
ALREADY_AUTHORIZED_OTHER_CONTENTLa DIAN autorizó ese número con otro contenido. El documento enviado no se marcó como válido.No lo reenvíes con ese número; consulta el documento autorizado.
ALREADY_PROCESSED_NOT_CONFIRMEDLa DIAN indicó que lo procesó, pero no confirmó la autorización.Consulta su estado antes de reenviarlo.

⚠️ Avisos posteriores a la aceptación: PDF_NOT_GENERATED / EMAIL_NOT_SENT / ATTACHED_DOCUMENT_NOT_GENERATED​

{
"warnings": [
{
"code": "PDF_NOT_GENERATED",
"message": "El documento fue validado por la DIAN, pero no se pudo generar la representación gráfica. No reenvíe el documento: ya es válido ante la DIAN."
}
]
}

Causa: la DIAN validó el documento, pero falló un paso posterior (PDF, correo o AttachedDocument).

Solución: no reenvíes el documento: ya es válido. Genera el PDF con POST /documents/pdf/{trackId}?regenerate=1 o reenvía el correo con POST /documents/sendmail/{trackId}. Ver Avisos de la respuesta.

📦 Envío masivo: DUPLICATE_DOCUMENT_UUID y POSSIBLY_SENT​

  • DUPLICATE_DOCUMENT_UUID: el item termina en FAILED porque la empresa ya emitió un documento con ese uuid. No se emite de nuevo; consulta el documento existente con GET /documents/{uuid}.
  • POSSIBLY_SENT: el item no obtuvo una respuesta definitiva de la DIAN después de transmitirse. No lo reenvíes en otro lote; consulta su estado con GET /documents/{uuid} usando el document_uuid del item.

Más detalles en Envío Masivo de Documentos.


💱 Errores de Moneda y Exportación​

❌ "Moneda inválida para exportación"​

Respuesta del API:

{
"error": true,
"errors": [
{
"field": "currency_id",
"message": "No puedes usar COP en una exportación"
}
]
}
❌ Incorrecto:
{
"type_document_id": 8, // Exportación
"currency_id": 170, // COP ❌
"customer": { "country_id": "239" } // USA
}
✅ Correcto:
{
"type_document_id": 8, // Exportación
"currency_id": 272, // USD ✓
"customer": { "country_id": "239" } // USA
}

❌ "IVA no permitido en exportación"​

Respuesta del API:

{
"error": true,
"errors": [
{
"field": "lines[0].tax_totals",
"message": "Las exportaciones no pueden tener IVA"
}
]
}

Incorrecto:

{
"tax_totals": [
{
"tax_id": "1",
"tax_amount": 19.00,
"percent": 19
}
]
}

❌ INCORRECTO: Los documentos de exportación no pueden tener impuestos

Correcto:

{
"tax_totals": []
}

✓ CORRECTO: Array vacío para exportaciones


🎯 Matriz de Solución Rápida​

⚡ Referencia Rápida de Errores

Encuentra rápidamente la solución al error que estás experimentando:

🔍 Síntoma🐛 Causa Probable✅ Solución
401 Unauthorized🔐 Token expirado🔄 Obtén nuevo token
invalid_json📝 JSON malformado✔️ Valida sintaxis JSON
NIT verificador inválido🔢 Dígito incorrecto🔍 Usa herramienta NITValidator
Total no coincide🧮 Cálculo de suma📊 Valida con TotalCalculator
Tax not calculated correctly💰 Fórmula impuesto🎯 Usa: amount = base × (percent/100)
400 ... ya se encuentra validado.🔄 Número ya validado🔍 Consulta GET /status; ➕ usa el siguiente número
409 DOCUMENT_IN_TRANSMISSION🚦 Envío en paralelo del mismo número⏳ Espera y consulta el estado; no reenvíes en paralelo
409 DOCUMENT_IN_VALIDATION⏳ La DIAN sigue en 98🔍 Consulta el estado en unos minutos con data.document_key
503 DIAN_STATUS_UNAVAILABLE🔌 No se confirmó el envío anterior (no se transmitió)🔄 Reintenta más tarde con el mismo número
DOCUMENT_POSSIBLY_SENT📡 Fallo después de transmitir🚫 No reemitas; consulta GET /documents/{uuid}
409 uuid ya se usó🆔 uuid anti-duplicados repetido🔍 Consulta ese documento o usa un uuid nuevo
warnings ALREADY_*🔁 Regla 90 conciliada📖 Revisa el code del aviso
warnings PDF_NOT_GENERATED / EMAIL_NOT_SENT📄 Falló un paso posterior✅ Documento válido: no lo reenvíes
Currency invalid for export💱 Moneda incorrecta💵 Usa currency_id: 272 (USD)
Tax not allowed in export🌎 IVA en exportación❌ Usa tax_totals: []
Discount exceeds amount🏷️ Descuento > base⚖️ Asegura que amount ≤ base_amount
Required field missing📋 Campo faltante📖 Consulta documentación

🛠️ Herramientas Disponibles​

💡 Prevención de Errores

Para evitar errores, usa nuestras herramientas interactivas:

🔍 NITValidator
Valida y calcula dígito verificador

✅ JSONValidator
Valida estructura completa

🧮 TotalCalculator
Calcula totales automáticamente


🔬 Debugging​

🎯 Guía de Depuración Paso a Paso
Sigue estos pasos para identificar y resolver problemas:

📡 Paso 1: Verificar Respuesta Completa​

curl -X POST "{{url}}/invoice" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d @factura.json \
-v # Modo verbose para ver toda la respuesta

✔️ Paso 2: Validar Localmente​

# Instalar jq para parsear JSON
npm install -g jq

# Validar que el JSON sea válido
cat factura.json | jq empty

📚 Paso 3: Comparar con Ejemplo Real​


🎯 Próximos Pasos​


📅 Última actualización: Febrero 2026 • ⏱️ Tiempo estimado: 30 minutos • 🎯 Nivel: ⭐⭐ Intermedio