Errores
Comprende los códigos de error y cómo manejarlos en tu integración
Estructura de Error Estándar
La mayoría de errores de la API siguen esta estructura simple con message y statusCode:
Error 401 - API Key Inválida
{
"message": "Unauthorized",
"statusCode": 401
}Sin embargo, los errores de validación (400) incluyen detalles más específicos:
Error 400 - Validación de Items
1{
2 "mensaje": "📝 Items inválidos",
3 "errores": [
4 {
5 "item": 1,
6 "campo": "precioUni",
7 "valor": -10,
8 "regla": "El precio unitario debe ser mayor o igual a 0"
9 }
10 ],
11 "statusCode": 400
12}Códigos de Estado HTTP
400Petición Incorrecta
La petición contiene parámetros inválidos o faltantes. Revisa la estructura de tu payload.
401No Autorizado
API key faltante, inválida, expirada o eliminada
403Prohibido
Has alcanzado el límite de tu cuota mensual de DTEs
404No Encontrado
El recurso solicitado no existe o el endpoint no es válido
429Límite de Velocidad Excedido
Has excedido el límite de peticiones por segundo/minuto. Revisa los headers de rate limit.
500Error del Servidor
Error interno del servidor o del Ministerio de Hacienda. Reintenta más tarde.
Errores de Autenticación (401)
API Key Inválida o Faltante
{
"message": "Unauthorized",
"statusCode": 401
}API Key Expirada
{
"message": "API Key expirada",
"statusCode": 401
}API Key Eliminada
{
"message": "API Key eliminada",
"statusCode": 401
}Errores de Validación (400)
Errores de Items
Validaciones específicas de los items del DTE
1{
2 "mensaje": "📝 Items inválidos",
3 "errores": [
4 {
5 "item": 1,
6 "campo": "cantidad",
7 "valor": 0,
8 "regla": "La cantidad debe ser mayor a 0"
9 },
10 {
11 "item": 2,
12 "campo": "descripcion",
13 "regla": "La descripción es requerida"
14 }
15 ],
16 "statusCode": 400
17}Errores de Pagos
Validaciones de los pagos del DTE
1{
2 "mensaje": "💰 Pagos inválidos",
3 "errores": [
4 {
5 "pago": 1,
6 "campo": "montoPago",
7 "valor": -100,
8 "regla": "El monto de pago debe ser mayor a 0"
9 }
10 ],
11 "sugerencia": "Revise los montos de los pagos",
12 "statusCode": 400
13}Error de Totales
Cuando los totales no cuadran con una tolerancia de $0.01
1{
2 "mensaje": "🧮 Totales incorrectos",
3 "esperado": 150.00,
4 "recibido": 148.50,
5 "diferencia": 1.50,
6 "sugerencia": "La diferencia excede la tolerancia de $0.01",
7 "statusCode": 400
8}Error de Schema JSON
Cuando el DTE no cumple con el schema oficial del Ministerio de Hacienda
1{
2 "mensaje": "❌ El DTE no cumple con el schema JSON del Ministerio de Hacienda",
3 "errores": [
4 {
5 "path": "/receptor/numDocumento",
6 "message": "must match pattern \"^[0-9]{4}-[0-9]{6}-[0-9]{3}-[0-9]$\"",
7 "expected": "NIT con formato 0614-010190-103-1"
8 }
9 ],
10 "statusCode": 400
11}Errores de Cuota (403)
Cuota Mensual Agotada
1{
2 "mensaje": "🚫 Cuota de DTEs agotada",
3 "usado": 30,
4 "limite": 30,
5 "plan": "FREE",
6 "sugerencia": "Actualiza tu plan para emitir más DTEs este mes",
7 "statusCode": 403
8}Errores del Ministerio de Hacienda (500)
Estos errores provienen directamente del Ministerio de Hacienda cuando el DTE es rechazado:
Respuesta de Error del MH
Cuando el MH rechaza el DTE, la respuesta incluye códigos y observaciones específicas
1{
2 "estado": "RECHAZADO",
3 "codigoGeneracion": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
4 "fhProcesamiento": "2025-01-16T10:30:05.000Z",
5 "codigoMsg": "801",
6 "descripcionMsg": "Certificado de firma inválido o expirado",
7 "observaciones": [
8 "El certificado X.509 ha expirado",
9 "Debe renovar su certificado digital ante el Ministerio de Hacienda"
10 ],
11 "clasificaMsg": "ERROR"
12}Códigos Comunes del MH
001Procesado correctamente ✅
801Certificado inválido o expirado
802Número de control duplicado
803Establecimiento no registrado
804NIT del emisor inválido
805Firma digital inválida
Rate Limiting (429)
La API implementa rate limiting en 3 niveles:
Short
3 req/segundoMáximo 3 peticiones por segundo
Medium
20 req/10sMáximo 20 peticiones cada 10 segundos
Long
100 req/minutoMáximo 100 peticiones por minuto
Headers de Rate Limit
Headers en cada respuesta
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642341600Error 429
{
"message": "ThrottlerException: Too Many Requests",
"statusCode": 429
}Manejo Recomendado
Ejemplo completo de manejo de errores
1async function emitirDTE(dteData) {
2 try {
3 const response = await fetch('http://localhost:3000/factura/emitir', {
4 method: 'POST',
5 headers: {
6 'X-API-Key': 'sk_user_tu_hash_aqui',
7 'Content-Type': 'application/json'
8 },
9 body: JSON.stringify(dteData)
10 });
11
12 if (!response.ok) {
13 const error = await response.json();
14
15 // Manejar diferentes tipos de error
16 switch (response.status) {
17 case 400:
18 console.error('Error de validación:', error.mensaje);
19 if (error.errores) {
20 console.error('Detalles:', error.errores);
21 }
22 // NO reintentar - corregir datos
23 break;
24
25 case 401:
26 console.error('API key inválida:', error.message);
27 // NO reintentar - verificar API key
28 break;
29
30 case 403:
31 console.error('Cuota agotada:', error.mensaje);
32 console.log('Plan actual:', error.plan);
33 console.log('Usado:', error.usado, 'de', error.limite);
34 // NO reintentar - actualizar plan
35 break;
36
37 case 429:
38 console.log('Rate limit excedido, esperando...');
39 const resetTime = response.headers.get('X-RateLimit-Reset');
40 const waitTime = (resetTime * 1000) - Date.now();
41 await new Promise(resolve => setTimeout(resolve, waitTime));
42 // REINTENTAR después de esperar
43 return emitirDTE(dteData);
44
45 case 500:
46 console.error('Error del servidor:', error.message);
47 // REINTENTAR con backoff exponencial
48 await new Promise(resolve => setTimeout(resolve, 5000));
49 return emitirDTE(dteData);
50
51 default:
52 console.error('Error desconocido:', error);
53 }
54
55 throw new Error(error.message || error.mensaje);
56 }
57
58 const resultado = await response.json();
59
60 // Verificar estado del MH
61 if (resultado.estado === 'RECHAZADO') {
62 console.error('DTE rechazado por Hacienda');
63 console.error('Código:', resultado.codigoMsg);
64 console.error('Descripción:', resultado.descripcionMsg);
65 console.error('Observaciones:', resultado.observaciones);
66 throw new Error(resultado.descripcionMsg);
67 }
68
69 console.log('✅ DTE emitido exitosamente');
70 console.log('Código de generación:', resultado.codigoGeneracion);
71 console.log('Número de control:', resultado.numeroControl);
72
73 return resultado;
74
75 } catch (error) {
76 console.error('Error al emitir DTE:', error);
77 throw error;
78 }
79}Mejores Prácticas
Recomendaciones
- • 400 Bad Request: NO reintentar. Corregir los datos del payload.
- • 401 Unauthorized: NO reintentar. Verificar API key válida y no expirada.
- • 403 Forbidden: NO reintentar. Actualizar plan o esperar al próximo ciclo.
- • 429 Too Many Requests: SÍ reintentar. Respetar headers X-RateLimit-Reset.
- • 500 Internal Server Error: SÍ reintentar con backoff exponencial (5s, 10s, 20s).
- • Registrar todos los errores incluyendo
codigoGeneracionpara auditoría. - • Guardar las
observacionesdel MH para debugging. - • Usar timeouts apropiados (30-60 segundos para emisión de DTEs).
- • Monitorear headers de rate limit para evitar errores 429.