Manejo de errores
Formato de respuesta de error
Todos los errores de la API siguen una estructura JSON consistente con un código de estado HTTP apropiado:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description of what went wrong"
}
}El campo code es un identificador estable y legible por máquinas que puedes usar en tu lógica de manejo de errores. El campo message proporciona contexto adicional y puede variar entre ocurrencias del mismo código de error.
Categorías de errores
Errores de autenticación (401)
Se devuelven cuando la solicitud no puede ser autenticada.
| Código | Descripción |
|---|---|
UNAUTHORIZED | El encabezado Authorization falta, está mal formado o contiene un token inválido. |
KEY_EXPIRED | La clave API era válida pero ha pasado su fecha de expiración. Crea una nueva clave para continuar. |
{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing or invalid Authorization header"
}
}Errores de autorización (403)
Se devuelven cuando el usuario autenticado no tiene permiso para acceder al recurso solicitado.
| Código | Descripción |
|---|---|
FORBIDDEN | Estás intentando acceder o modificar un recurso que pertenece a otro usuario (por ejemplo, revocar la clave API de otra persona). |
Errores de no encontrado (404)
Se devuelven cuando el recurso solicitado no existe.
| Código | Descripción |
|---|---|
NOT_FOUND | El recurso identificado en la URL (extracción, clave API, etc.) no existe o ha sido eliminado. |
Errores de validación (400)
Se devuelven cuando el cuerpo de la solicitud o los parámetros son inválidos.
| Código | Descripción |
|---|---|
VALIDATION_ERROR | El cuerpo de la solicitud no pasó la validación del esquema. El campo message describe qué campos son inválidos. |
MAX_KEYS_REACHED | Has alcanzado el máximo de 10 claves API activas. Revoca una clave existente antes de crear una nueva. |
{
"error": {
"code": "MAX_KEYS_REACHED",
"message": "Maximum of 10 active API keys allowed"
}
}Errores de límite de uso (429)
Se devuelven cuando se han excedido los límites de uso.
| Código | Descripción |
|---|---|
USAGE_LIMIT_EXCEEDED | Se ha alcanzado tu límite mensual de extracciones. Mejora tu plan o espera hasta el próximo período de facturación. |
{
"error": {
"code": "USAGE_LIMIT_EXCEEDED",
"message": "Monthly extraction limit reached (25/25). Upgrade your plan for more extractions."
}
}Errores del servidor (500)
Se devuelven cuando algo inesperado ocurre en el lado del servidor.
| Código | Descripción |
|---|---|
INTERNAL_ERROR | Ocurrió un error inesperado del servidor. Estos se registran e investigan automáticamente. |
EXTRACTION_FAILED | El pipeline de procesamiento con IA encontró un error al extraer datos de tu documento. El documento puede estar corrupto, ilegible o en un formato no compatible. |
Errores reintentables
No todos los errores deben reintentarse. Aquí hay un desglose:
| Código | Reintentable | Acción |
|---|---|---|
INTERNAL_ERROR | Sí | Reintentar con retroceso exponencial |
EXTRACTION_FAILED | Sí | Reintentar -- la IA puede producir un resultado diferente. Si persiste, verificar la calidad del documento |
USAGE_LIMIT_EXCEEDED | No | Mejorar tu plan o esperar hasta el próximo período de facturación |
UNAUTHORIZED | No | Corregir tus credenciales de autenticación |
KEY_EXPIRED | No | Crear una nueva clave API |
FORBIDDEN | No | Estás accediendo a un recurso que no te pertenece |
NOT_FOUND | No | El recurso no existe -- verificar el ID |
VALIDATION_ERROR | No | Corregir el cuerpo de la solicitud para que coincida con el esquema esperado |
MAX_KEYS_REACHED | No | Revocar una clave existente antes de crear una nueva |
Estrategia de reintento
Para errores reintentables, usa retroceso exponencial para evitar sobrecargar el servidor. Aquí hay una implementación reutilizable:
interface ApiResponse<T> {
data?: T;
error?: { code: string; message: string };
}
async function fetchWithRetry<T>(
url: string,
options: RequestInit,
maxRetries = 3,
): Promise<ApiResponse<T>> {
let lastError: Error | null = null;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
const body = await response.json();
if (response.ok) {
return body as ApiResponse<T>;
}
const errorCode = body?.error?.code;
// Only retry server errors
if (
(errorCode === "INTERNAL_ERROR" || errorCode === "EXTRACTION_FAILED") &&
attempt < maxRetries
) {
const delayMs = 1000 * Math.pow(2, attempt); // 1s, 2s, 4s
console.log(`Retrying in ${delayMs}ms (attempt ${attempt + 1}/${maxRetries})...`);
await new Promise((resolve) => setTimeout(resolve, delayMs));
continue;
}
// Non-retryable error -- return immediately
return body as ApiResponse<T>;
} catch (err) {
lastError = err as Error;
if (attempt < maxRetries) {
const delayMs = 1000 * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delayMs));
continue;
}
}
}
throw lastError ?? new Error("Max retries exceeded");
}Uso:
const result = await fetchWithRetry<ExtractionResult>(
"https://api.docmap.io/v1/extractions/run",
{
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "tmpl_abc123",
fileName: "invoice.pdf",
pdfBase64: encodedPdf,
mimeType: "application/pdf",
}),
},
);
if (result.error) {
console.error(`Extraction failed: [${result.error.code}] ${result.error.message}`);
} else {
console.log("Extracted data:", result.data);
}Mejores prácticas
Siempre verifica primero el código de estado HTTP. Un estado
2xxsignifica éxito; cualquier otra cosa es un error. No asumas que el cuerpo de la respuesta tiene un campodatasin verificar.Analiza el cuerpo del error para obtener el campo
code. Usacode(nomessage) en tu flujo de control. Los mensajes de error pueden cambiar con el tiempo, pero los códigos de error son estables.Maneja códigos de error específicos. Ramifica según códigos conocidos como
USAGE_LIMIT_EXCEEDEDoKEY_EXPIREDpara mostrar mensajes específicos a tus usuarios o activar flujos de trabajo particulares.Registra los errores desconocidos. Si encuentras un código de error que no manejas explícitamente, registra la respuesta completa (código de estado, código de error y mensaje) para depuración.
No reintentes errores 4xx. Los errores de autenticación, autorización, validación y no encontrado no se resolverán por sí solos. Corrige el problema subyacente antes de reintentar.
Establece un límite de reintentos. Nunca reintentes indefinidamente. Tres reintentos con retroceso exponencial (1s, 2s, 4s) es un valor predeterminado razonable para errores del servidor.
