Cómo son las respuestas de error de la API de LinkHarbor, qué significan los códigos de error más importantes y cómo debe reaccionar tu código.
Todas las respuestas de error de la API tienen el mismo formato. Tu código debe basarse en el código de error del campo error, no en el texto de message: el código se mantiene estable, mientras que el texto puede cambiar y se traduce al idioma de la cuenta.
Estructura de una respuesta de error
{
"error": "validation_failed",
"message": "Some of the information provided is invalid. Please check and try again.",
"details": [
{ "field": "title", "reason": "minLength", "message": "…" }
],
"request_id": "6b1f0c2e-…"
} - error
- Código legible por máquinas, por ejemplo not_found. En la mayoría de los errores también aparece en el encabezado X-Error-Code, pero básate en el campo del cuerpo.
- message
- Descripción legible para personas en el idioma de la cuenta: con una clave de API, el del propietario del espacio de trabajo; con una app conectada, el de la persona que la conectó. Sin un token válido (por ejemplo, el 401 de la comprobación del token), el idioma sigue a Accept-Language; si no, es inglés. El encabezado Content-Language indica el idioma.
- details
- Solo aparece cuando hay algo más que decir. Para un 422 de la validación de la entrada, una lista con field, reason y message para cada problema; para un 422 de la lógica de negocio y todos los demás errores, un objeto, por ejemplo con reason, retry_after_sec o una lista de issues. Cuando se supera un tamaño contiene field, reason y limit, y en 413 request_too_large, max_bytes y max_kb. Así que comprueba si details es una lista.
- request_id
- El ID de la petición. También está en el encabezado X-Request-Id. Inclúyelo cuando contactes con soporte.
Excepciones: la respuesta 429 rate_limited tiene el campo retry_after_sec en lugar de details; con 429 y con 403 insufficient_scope, falta request_id en el cuerpo. El 401 de la comprobación del token y el 422 de la comprobación del esquema no llevan el encabezado X-Error-Code; en la comprobación del esquema solo se traduce el message principal, los textos de details siguen en inglés. El encabezado X-Request-Id siempre está presente.
Los códigos más importantes
| HTTP | error | Significado | Qué hacer |
|---|---|---|---|
| 400 | invalid_json | El cuerpo no es un JSON válido | Revisa el JSON |
| 400 | bad_request | Content-Type incorrecto o petición mal formada | Pon Content-Type: application/json |
| 401 | missing_bearer_token | No hay token en el encabezado Authorization | Pon el encabezado Authorization: Bearer … |
| 401 | invalid_token | Token caducado o no válido, o clave eliminada | Pide un token nuevo; si no ayuda, revisa la clave |
| 401 | invalid_api_key | ID o secreto de la clave incorrectos en el intercambio de token | Revisa las credenciales |
| 402 | plan_limit_reached | Límite del plan alcanzado, por ejemplo de enlaces cortos | Mejora el plan o elimina entradas |
| 403 | insufficient_scope | Falta el scope o el endpoint no está habilitado para claves de API | Crea una clave con el scope adecuado |
| 403 | forbidden | Sin permiso para esta acción | Hazlo en el panel |
| 403 | feature_not_available | Función no incluida en el plan | Revisa el plan |
| 403 | block_type_requires_plan | Tipo de bloque disponible solo en un plan superior | Elige otro tipo de bloque o mejora el plan |
| 403 | template_locked | Plantilla premium no disponible en el plan actual | Elige una plantilla de GET /v1/templates/available |
| 403 | workspace_suspended, workspace_read_only, workspace_grace_expired | Espacio de trabajo bloqueado o de solo lectura por un pago pendiente | Resuelve el pago en el panel |
| 404 | not_found | El recurso no existe o no pertenece a tu espacio de trabajo | Revisa el ID |
| 409 | conflict | Conflicto general con el estado actual | Vuelve a cargar el estado y cambia la entrada |
| 409 | workspace_template_in_use | Hay páginas que todavía usan la plantilla del espacio de trabajo; el número está en details.count | Cambia las páginas a otra plantilla y después elimínala |
| 409 | handle_taken, slug_taken | El handle o el slug del enlace corto ya está en uso | Elige otro valor |
| 409 | form_in_use, page_not_private, page_not_published, never_published | Conflicto con el estado: el formulario sigue en una página, la página no es privada o no está publicada, nunca se ha publicado | Cambia el estado y vuelve a intentarlo |
| 409 | page_limit_reached, link_limit_reached, block_limit_reached, form_limit_reached, asset_limit_reached, asset_storage_limit_reached, workspace_template_limit_reached | Se ha alcanzado el límite de cantidad o de almacenamiento del plan | Quita entradas o mejora el plan |
| 409 | draft_not_publishable | El borrador tiene problemas; la lista está en details.issues | Corrige los problemas y vuelve a publicar |
| 413 | request_too_large | Cuerpo mayor de lo permitido para este endpoint (64 KB, 1 MB o 2 MB); el límite está en details.max_kb | Envía menos datos por petición; consulta Límites de peticiones |
| 413 | payload_too_large | Archivo subido mayor de 10 MB | Reduce el tamaño del archivo |
| 422 | validation_failed | Entrada no válida o campo desconocido; los detalles están en details | Corrige los campos como se indica en details |
| 422 | handle_reserved, target_url_invalid, target_url_scheme, target_url_host | Handle reservado, o URL de destino no válida o no permitida | Elige otro valor |
| 422 | workspace_template_disabled | La plantilla del espacio de trabajo elegida está desactivada | Activa la plantilla en «Dominios y plantillas» o elige otra |
| 422 | template_css_external, template_section_invalid | Plantilla del espacio de trabajo: el CSS carga desde servidores externos, o una sección {{#if}}/{{#unless}}/{{#each}} está mal colocada | Quita las direcciones externas o cierra la sección dentro de la misma etiqueta o del mismo texto |
| 422 | custom_css_external | El CSS personalizado carga algo desde servidores externos | Quita las direcciones externas del CSS |
| 429 | rate_limited, api_key_locked | Demasiadas peticiones, o clave bloqueada tras intentos fallidos | Espera lo que indique Retry-After o details.retry_after_sec |
| 500 | internal_error | Error inesperado | Vuelve a intentarlo más tarde y anota el request_id |
| 503 | service_unavailable | Servicio no disponible temporalmente | Vuelve a intentarlo tras una pausa |
Leer los errores de entrada
Con 422 validation_failed, details enumera cada problema por separado: field es la ruta del campo (con barras para los objetos anidados, por ejemplo theme_config/button_style) y reason es la regla incumplida, como required, minLength, maxLength, enum o additionalProperties. Con additionalProperties, el mensaje dice qué campos son desconocidos; a menudo es una errata en el nombre del campo.
Gestión recomendada en tu código
- 400, 413 y 422: no repitas la petición; corrígela
- 401 invalid_token: pide un token nuevo una vez y repite la petición
- 403: no repitas la petición; revisa el scope, el plan o quién puede hacer esto
- 404: revisa el ID; después de una eliminación es lo normal
- 409: vuelve a cargar el estado y decide si la acción sigue haciendo falta
- 429: espera lo que indique Retry-After y repite la petición; consulta Límites de peticiones
- 500 y 503: repite unas pocas veces con pausas cada vez más largas
También te puede ser útil
¿No has encontrado nada?
Cuéntanos qué necesitas y nuestro equipo de soporte te ayudará personalmente.