FeniciaDocs
DocumentaciónAPICambiosSoporte
Buscar⌘K
API de ÓrdenesListar PedidosCrear un pedidoBuscar PedidosConsultar un pedidoActualizar un pedidoTransiciones de Estado de PedidosPreparación y EnvíoDevoluciones y ReembolsosAdjuntosHistorial y ExportaciónCarritos AbandonadosCatálogo de Errores

Producto

  • Características
  • Precios
  • Integraciones

Recursos

  • Documentación
  • API
  • Cambios
  • Blog

Empresa

  • Sobre nosotros
  • Contacto
  • Carreras

Legal

  • Privacidad
  • Términos
FeniciaLa plataforma de e-commerce para merchants profesionales

© 2026 Hobbio Inc. Todos los derechos reservados.

Catálogo de Errores

Todos los errores de la API de Fenicia siguen un formato JSON consistente. Esta página es la referencia canónica para cada código de error que puede devolver la API de Pedidos.

Forma de la respuesta de error

{
  "code": "INVALID_API_KEY",
  "message": "API key inválida o expirada"
}

Algunos errores incluyen campos adicionales (por ejemplo retryAfter en respuestas de rate limit, o details en errores de validación).

{
  "code": "validation:invalid_format",
  "message": "El campo 'customerInfo.email' tiene un formato inválido",
  "details": { "field": "customerInfo.email", "expected": "email" }
}

Errores de autenticación (401)

CódigoDescripción
MISSING_AUTHORIZATIONNo se envió el header Authorization
INVALID_AUTHORIZATION_FORMATEl header no sigue el formato Bearer <key>
INVALID_API_KEYLa API key no existe, expiró o fue revocada
{ "code": "INVALID_API_KEY", "message": "API key inválida o expirada" }

Errores de permisos (403)

CódigoDescripción
INSUFFICIENT_PERMISSIONSLa API key no tiene el scope requerido para este endpoint
account/billing_restrictedEl tenant está suspendido por problemas de facturación
{
  "code": "INSUFFICIENT_PERMISSIONS",
  "message": "La API key no tiene el scope requerido: orders:create"
}

Errores de validación (400)

CódigoDescripción
validation:missing_fieldFalta un campo obligatorio
validation:invalid_formatEl campo tiene un formato incorrecto (email, fecha, UUID, etc.)
validation:invalid_valueValor no permitido (enum inválido, fuera de rango)
{
  "code": "validation:missing_field",
  "message": "El campo 'customerInfo.email' es obligatorio",
  "details": { "field": "customerInfo.email" }
}

No encontrado (404)

CódigoDescripción
order_not_foundNo existe un pedido con el ID dado para este tenant
return_not_foundNo existe una devolución con el ID dado
attachment_not_foundNo existe un adjunto con el ID dado
{ "code": "order_not_found", "message": "Pedido ord_123 no encontrado" }

Errores de lógica de negocio (409)

CódigoDescripción
invalid_transitionNo se puede transicionar al estado destino desde el estado actual
order_already_cancelledEl pedido ya está cancelado
insufficient_inventoryInventario insuficiente para cumplir el pedido
{
  "code": "invalid_transition",
  "message": "No se puede transicionar de 'cancelled' a 'fulfilled'"
}

Rate limit (429)

CódigoDescripción
RATE_LIMIT_EXCEEDEDSe excedió la tasa de peticiones. Inspecciona retryAfter (segundos) para saber cuándo reintentar
{
  "code": "RATE_LIMIT_EXCEEDED",
  "message": "Demasiadas peticiones",
  "retryAfter": 45
}

Advertencia

Respeta siempre retryAfter. Reintentar antes mantendrá tu acceso bloqueado y puede disparar cooldowns más largos.


Errores del servidor (5xx)

CódigoEstadoDescripción
INTERNAL_ERROR500Error genérico del servidor. Transitorio, seguro reintentar con backoff
EXTERNAL_SERVICE_UNAVAILABLE503El canal o proveedor de pagos externo no está disponible
{
  "code": "EXTERNAL_SERVICE_UNAVAILABLE",
  "message": "La API de Shopify no está disponible"
}

Mejores prácticas

Reintentos con backoff exponencial

Para errores transitorios (500, 503, timeouts de red), reintenta con backoff exponencial — duplicando el retraso en cada intento.

async function requestWithRetry(url, options, maxRetries = 5) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const res = await fetch(url, options);
 
    if (res.status === 429) {
      const { retryAfter = 1 } = await res.json();
      await sleep(retryAfter * 1000);
      continue;
    }
 
    if (res.status >= 500) {
      const delay = Math.min(1000 * 2 ** attempt, 30_000);
      await sleep(delay);
      continue;
    }
 
    return res;
  }
  throw new Error("Máximo de reintentos alcanzado");
}
 
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

Cuándo reintentar y cuándo fallar rápido

Estado¿Reintentar?Estrategia
400 validaciónNoCorregir la petición, propagar el error al llamador
401 authNoRotar la key o re-autenticar
403 permisosNoSolicitar un upgrade de scope
404 no encontradoNoEl recurso no existe
409 lógica de negocioA vecesSolo si puedes mutar el estado para resolver el conflicto
429 rate limitSíEsperar retryAfter y reintentar
500 internoSíBackoff exponencial, hasta ~5 intentos
503 externo caídoSíBackoff más largo — la dependencia se está recuperando

Idempotencia

Los endpoints mutables (POST, PUT, DELETE) aceptan un header Idempotency-Key. Úsalo al reintentar para evitar crear recursos duplicados:

curl -X POST https://api.fenicia.io/orders \
  -H "Authorization: Bearer fn_live_tu_api_key" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{...}'

Tip

Genera una clave de idempotencia nueva por operación lógica, pero reutiliza la misma clave en los reintentos de esa operación. Guárdala junto a la operación hasta recibir una respuesta exitosa.

Loguea el code, no el message

Los mensajes de error pueden estar traducidos o cambiar con el tiempo. Los códigos son estables — ramifica tu lógica por code en tu integración, no por el texto del mensaje.

// Correcto
if (error.code === "insufficient_inventory") {
  await notifyMerchant(order);
}
 
// Frágil
if (error.message.includes("stock")) { ... }

¿Necesitas ayuda?

  • Autenticación
  • Contacta a soporte: support@fenicia.io