Categorías

Este dominio cubre tres capas relacionadas pero distintas:

  1. Árbol de categorías Fenicia — la taxonomía propia de tu catálogo.
  2. Clasificación automática — endpoints que, dado un título/descripción de producto, sugieren una categoría o código fiscal usando IA: SAT (CFDI), T1/Sears/Sanborns, Walmart y TikTok Shop tienen su propio clasificador.
  3. Mapeos de categoría — la relación persistida entre una categoría Fenicia y su equivalente en un marketplace específico, con métricas de uso y un flujo de aprobación.

Base path distinto de /products

Este dominio vive bajo /categories, un recurso de API Gateway propio (fenicia-categories-{stage}) — no es un sub-recurso de /products. Usa https://api.fenicia.io/categories/... directamente.

Sin envelope único

Igual que el resto de la API de Productos, no hay un envelope {data, meta} uniforme aquí — cada endpoint devuelve su propio shape. Documentamos el shape real de cada uno; donde no fue verificado campo por campo en la auditoría, lo señalamos explícitamente.

Autenticación: Authorization: Bearer fkapi_..., salvo el único endpoint marcado explícitamente como público más abajo (GET /categories/sat/search). El resto exige tenantId resuelto (401 si falta) y, en la mayoría de las rutas, un permiso RBAC específico — ver la nota sobre las cuatro excepciones más abajo.

Árbol y búsqueda de categorías

Devuelve el árbol completo de categorías de tu tenant (también accesible en GET /categories, sin sufijo)

localestring

Idioma de las etiquetas. Default 'es'.

200
[
  {
    "id": "cat-ropa",
    "name": "Ropa",
    "children": [
      { "id": "cat-ropa-playeras", "name": "Playeras", "children": [] }
    ]
  }
]
500
{ "success": false, "error": "Failed to load category tree", "code": "INTERNAL_ERROR" }

Permiso requerido: products:read

Busca categorías de tu tenant por texto

qstringrequired

Término de búsqueda.

localestring

Idioma de las etiquetas.

limitnumber

Límite de resultados. Default 20.

400
{ "success": false, "error": "Search query is required", "code": "MISSING_PARAMETER" }

Permiso requerido: products:read

Clasificación SAT (CFDI)

Sugiere el código SAT (clave de producto/servicio) apropiado para facturación electrónica a partir del título y datos de un producto.

Busca claves de producto/servicio SAT por texto

qstringrequired

Término de búsqueda.

limitnumber

Límite de resultados.

400
{ "success": false, "error": "Search query is required", "code": "MISSING_PARAMETER" }

Endpoint público — sin autenticación

A diferencia de todos los demás endpoints de esta página (y de la API en general), GET /categories/sat/search no requiere Authorization. Es el único endpoint público de este dominio, consistente con que el catálogo SAT es información pública del catálogo del SAT mexicano, no datos de tu tenant.

Sugiere el código SAT para un producto a partir de su título/datos

titlestringrequired

Título del producto.

{ "title": "Camisa de algodón manga larga" }
200
{
  "satCode": "53101600",
  "description": "Camisas",
  "confidence": 0.92,
  "method": "ai",
  "processingTimeMs": 340
}
400
{ "code": "MISSING_PARAMETER", "message": "Product title is required" }

Permiso requerido: products:read

Efecto secundario: emite un evento

Cada llamada exitosa a POST /categories/sat/suggest emite un evento sat-categorization a EventBridge — útil si necesitas reaccionar a clasificaciones SAT desde otro sistema, pero también significa que el endpoint no es una operación puramente de lectura pese a no persistir cambios visibles en el producto.

Métricas de cache y clasificación SAT

200
{
  "success": true,
  "data": {
    "service": {
      "version": "2.7.0",
      "architecture": "global_rag",
      "description": "Global RAG - works for ANY product from ANY industry"
    },
    "cache": {
      "enabled": true,
      "size": 128,
      "maxSize": 5000,
      "hitRate": "42.3%"
    },
    "metrics": {
      "enabled": true,
      "classification": {
        "total": 340,
        "successful": 332,
        "failed": 8,
        "avgConfidence": "88.5%",
        "avgProcessingTimeMs": 410
      },
      "methods": {
        "globalRagLlm": 210,
        "globalRagOnly": 122
      },
      "tokens": {
        "input": 42000,
        "output": 21000,
        "estimatedCostUsd": "$0.6300"
      }
    }
  }
}
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: settings:read

Reinicia las métricas SAT y, opcionalmente, limpia el cache de clasificación

clearCacheboolean

Si es `true`, también limpia el cache de clasificaciones SAT.

{ "clearCache": true }
200
{ "success": true, "message": "Stats reset" }

Permiso requerido: settings:manage

Clasificación T1 / Sears / Sanborns

Clasifica un producto en la taxonomía de T1 (canal T1/Sears/Sanborns)

titlestringrequired

Título del producto y demás datos relevantes para la clasificación.

{ "title": "Camisa de algodón manga larga" }
200
{
  "t1CategoryId": "T1-12345",
  "t1CategoryPath": "Ropa > Playeras",
  "t1CategoryName": "Playeras",
  "segment": "ropa",
  "segmentName": "Ropa y Accesorios",
  "confidence": 0.91,
  "method": "global_rag_llm",
  "processingTimeMs": 480
}
400
{ "code": "MISSING_PARAMETER", "message": "Product title is required" }

Permiso requerido: products:read

Efecto secundario: emite un evento

Emite un evento t1-categorization a EventBridge en cada clasificación exitosa.

Métricas de clasificación T1

200
{
  "success": true,
  "data": {
    "service": {
      "version": "2.6.0",
      "architecture": "global_rag",
      "description": "Global RAG - works for ANY product from ANY industry"
    },
    "cache": {
      "enabled": true,
      "size": 96,
      "maxSize": 5000,
      "hitRate": "38.1%"
    },
    "metrics": {
      "enabled": true,
      "classification": {
        "total": 214,
        "successful": 208,
        "failed": 6,
        "avgConfidence": "86.2%",
        "avgProcessingTimeMs": 465
      },
      "methods": {
        "globalRagLlm": 150,
        "globalRagOnly": 58
      },
      "tokens": {
        "input": 30000,
        "output": 15000,
        "estimatedCostUsd": "$0.4500"
      }
    }
  }
}
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: settings:read

Reinicia las métricas T1, opcionalmente limpiando el cache

clearCacheboolean

Limpia el cache de clasificación T1.

{ "clearCache": true }
200
{ "success": true, "message": "Metrics reset, cache cleared" }
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: settings:manage

Categorías y clasificación Walmart

Devuelve el catálogo completo de categorías de Walmart (79 categorías)

200
{
  "total": 79,
  "categories": [
    { "id": "4044", "name": "Athletic Shoes", "segment": "shoes", "segmentName": "Calzado" },
    { "id": "5438", "name": "Shirts", "segment": "clothing", "segmentName": "Ropa y Accesorios" }
  ]
}
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: products:read

Busca en el catálogo de categorías de Walmart

qstringrequired

Término de búsqueda.

limitnumber

Límite de resultados.

400
{ "success": false, "error": "Search query is required", "code": "MISSING_PARAMETER" }

Permiso requerido: products:read

Clasifica un producto en la taxonomía de Walmart (motor de clasificación v5)

titlestringrequired

Título del producto y demás datos relevantes.

{ "title": "Tenis Nike Air Max 270" }
200
{
  "walmartCategoryId": "4044",
  "walmartCategoryName": "Athletic Shoes",
  "segment": "shoes",
  "segmentName": "Calzado",
  "visibleSectionMX": "Tenis deportivos",
  "productTypeName": "Athletic Shoes",
  "productTypeGroup": "Shoes",
  "category": "Clothing, Shoes & Accessories",
  "fullPath": "Clothing, Shoes & Accessories > Shoes > Athletic Shoes",
  "taxonomyVersion": "v5.0",
  "categoryStatus": "active",
  "requiredAttributes": ["brand", "size", "color"],
  "aiInferableAttributes": ["brand", "color"],
  "confidence": 0.89,
  "method": "global_rag_llm",
  "processingTimeMs": 520
}
400
{ "code": "MISSING_PARAMETER", "message": "Product title is required" }

Permiso requerido: products:read

Efecto secundario: emite un evento

Emite un evento interno de categorización a EventBridge en cada clasificación exitosa.

Resuelve, con IA, los valores de atributos requeridos por una categoría de Walmart para un producto dado

categoryIdstringrequired

ID de la categoría Walmart destino.

titlestringrequired

Título del producto.

descriptionstring

Descripción del producto.

brandstring

Marca.

categorystring

Categoría Fenicia del producto, como contexto adicional.

existingAttributesobject

Atributos ya conocidos, para no volver a resolverlos.

resolveVariantAttributestring

Nombre del atributo de variante a resolver específicamente (por ejemplo, tamaño o color).

allowedValuesarray

Restringe la resolución a este conjunto de valores permitidos.

attributeTypestring

Tipo de atributo a resolver.

{
  "categoryId": "4044",
  "title": "Playera de algodón manga larga",
  "description": "Playera 100% algodón, cuello redondo",
  "brand": "Fenicia Basics",
  "category": "Ropa > Playeras"
}
200Modo estándar: resuelve todos los atributos requeridos de la categoría
{
  "success": true,
  "categoryId": "4044",
  "resolvedAttributes": {
    "brand": { "name": "brand", "value": "Fenicia Basics", "confidence": 0.95, "source": "existing" },
    "color": { "name": "color", "value": "Azul", "confidence": 0.8, "source": "ai_inferred" }
  },
  "missingAttributes": ["size"],
  "processingTimeMs": 610
}
200Modo atributo de variante (resolveVariantAttribute=true)
{
  "success": true,
  "categoryId": "4044",
  "variantAttributeName": "Talla",
  "confidence": 0.93,
  "reasoning": "El producto tiene variantes por talla numérica.",
  "processingTimeMs": 340
}
400
{ "code": "MISSING_PARAMETER", "message": "categoryId is required" }

Permiso requerido: products:read

resolvedAttributes es un objeto, no un arreglo

A diferencia de POST /categories/generic/resolve-attributes y POST /categories/mercadolibre/resolve-attributes (que devuelven resolvedAttributes como arreglo), aquí es un objeto de pares atributo→detalle (Record<string, WalmartResolvedAttribute>), indexado por el nombre del atributo. source es uno de ai_inferred, default o existing.

Métricas de clasificación Walmart

200
{
  "success": true,
  "data": {
    "service": {
      "version": "2.8.0",
      "architecture": "global_rag",
      "description": "Global RAG - 79 Walmart categories",
      "totalCategories": 79
    },
    "cache": {
      "enabled": true,
      "size": 210,
      "maxSize": 5000,
      "hitRate": "51.4%"
    },
    "metrics": {
      "enabled": true,
      "classification": {
        "total": 512,
        "successful": 498,
        "failed": 14,
        "avgConfidence": "90.1%",
        "avgProcessingTimeMs": 530
      },
      "methods": {
        "globalRagLlm": 340,
        "globalRagOnly": 158
      },
      "tokens": {
        "input": 68000,
        "output": 34000,
        "estimatedCostUsd": "$1.0200"
      }
    }
  }
}
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: settings:read

Reinicia las métricas de clasificación Walmart

clearCacheboolean

Si es `true`, también limpia el cache de clasificaciones Walmart.

{ "clearCache": true }
200
{ "success": true, "message": "Metrics reset, cache cleared" }
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: settings:manage

Clasificación TikTok Shop

Clasifica un producto en la taxonomía de TikTok Shop

titlestringrequired

Título del producto y demás datos relevantes.

{ "title": "Blusa floral manga corta" }
200
{
  "tiktokCategoryId": "601001",
  "tiktokCategoryPath": "Ropa > Blusas y Camisas",
  "tiktokCategoryName": "Blusas y Camisas",
  "segment": "ropa",
  "segmentName": "Ropa y Accesorios",
  "confidence": 0.87,
  "method": "global_rag_llm",
  "processingTimeMs": 455
}
400
{ "code": "MISSING_PARAMETER", "message": "Product title is required" }

Permiso requerido: products:read

Efecto secundario: emite un evento

Emite un evento interno de categorización a EventBridge en cada clasificación exitosa.

Métricas de clasificación TikTok Shop

200
{
  "success": true,
  "data": {
    "service": {
      "version": "2.12.4",
      "architecture": "global_rag",
      "description": "Global RAG - ~2,700 TikTok Shop categories",
      "totalCategories": 2723
    },
    "cache": {
      "enabled": true,
      "size": 74,
      "maxSize": 5000,
      "hitRate": "29.6%"
    },
    "metrics": {
      "enabled": true,
      "classification": {
        "total": 130,
        "successful": 122,
        "failed": 8,
        "avgConfidence": "83.4%",
        "avgProcessingTimeMs": 490
      },
      "methods": {
        "globalRagLlm": 95,
        "globalRagOnly": 27
      },
      "tokens": {
        "input": 19000,
        "output": 9500,
        "estimatedCostUsd": "$0.2850"
      }
    }
  }
}
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: settings:read

Reinicia las métricas de clasificación TikTok Shop

clearCacheboolean

Si es `true`, también limpia el cache de clasificaciones TikTok Shop.

{ "clearCache": true }
200
{ "success": true, "message": "Metrics reset, cache cleared" }
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: settings:manage

Clasificación unificada y cache

Sin permiso RBAC explícito

Los cuatro endpoints de esta sección no llaman requirePermission() en el código fuente auditado — a diferencia de prácticamente todas las demás rutas de este dominio, solo validan que exista un tenantId resuelto (sesión autenticada válida), sin exigir un permiso adicional. No es un error de esta documentación: es el comportamiento real confirmado en el código. Si tu organización necesita restringir estas operaciones por rol, repórtalo a soporte.

Clasifica un producto probando en cascada las estrategias de clasificación disponibles (hasta 5), hasta obtener un resultado

titlestringrequired

Título del producto.

descriptionstring

Descripción del producto.

brandstring

Marca.

feniciaCategoryIdstring

Categoría Fenicia ya conocida del producto, como contexto.

skustring

SKU del producto.

categorystring

Categoría adicional de contexto.

{
  "title": "Playera de algodón manga larga",
  "description": "Playera 100% algodón, cuello redondo",
  "brand": "Fenicia Basics",
  "feniciaCategoryId": "cat-ropa-playeras",
  "sku": "PLA-001",
  "category": "Ropa > Playeras"
}
401
{ "success": false, "error": "Tenant ID required", "code": "UNAUTHORIZED" }
400
{ "success": false, "error": "Product title is required", "code": "MISSING_PARAMETER" }

Permiso requerido: ninguno explícito — solo sesión autenticada con tenantId resuelto.

Busca un resultado de clasificación ya cacheado, sin volver a ejecutar el clasificador

titlestringrequired

Título del producto.

descriptionstring

Descripción del producto.

brandstring

Marca.

marketplacestring

Restringe la búsqueda de cache a un marketplace específico.

{
  "title": "Playera de algodón manga larga",
  "description": "Playera 100% algodón, cuello redondo",
  "brand": "Fenicia Basics",
  "marketplace": "walmart"
}
200Encontrado en cache
{
  "success": true,
  "data": {
    "found": true,
    "classification": {
      "marketplace": "walmart",
      "categoryId": "4044",
      "categoryPath": "Clothing, Shoes & Accessories > Shoes > Athletic Shoes",
      "confidence": 0.89,
      "method": "global_rag_llm",
      "classifiedAt": "2026-07-10T15:22:00.000Z"
    }
  }
}
200Sin resultado en cache
{ "success": true, "data": { "found": false } }
401
{ "success": false, "error": "Tenant ID required", "code": "UNAUTHORIZED" }
400
{ "success": false, "error": "Product title is required", "code": "MISSING_PARAMETER" }

Permiso requerido: ninguno explícito — solo sesión autenticada.

Estadísticas del cache de clasificación

200
{
  "success": true,
  "data": {
    "service": {
      "version": "2.13.0",
      "description": "Persistent classification cache with confidence-based TTL"
    },
    "stats": {
      "totalEntries": 812,
      "totalHits": 2140,
      "avgHitCount": 2.64,
      "methodDistribution": { "binding": 40, "cache": 0, "mapping": 120, "rag": 380, "rag_llm": 272 },
      "marketplaceDistribution": { "walmart": 310, "mercadolibre": 260, "tiktok": 180 },
      "publicationSuccessRate": 0.94
    }
  }
}
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: ninguno explícito — solo sesión autenticada.

Invalida entradas del cache de clasificación

feniciaCategoryIdstring

Invalida solo las entradas asociadas a esta categoría Fenicia. Si se omite, aplica el criterio de `cleanup`.

cleanupboolean

Ejecuta una limpieza general de entradas expiradas/obsoletas.

{ "feniciaCategoryId": "cat-ropa-playeras", "cleanup": false }
200
{ "invalidatedCount": 12, "cleanedCount": 3 }

Permiso requerido: ninguno explícito — solo sesión autenticada.

Mapeos de categoría por marketplace

Un mapeo relaciona una categoría Fenicia con su equivalente en un marketplace, con métricas de uso (tasa de éxito) y un flujo de aprobación para mapeos generados automáticamente.

Busca el mapeo existente entre una categoría Fenicia y un marketplace

feniciaCategoryIdstringrequired

ID de la categoría Fenicia.

marketplacestringrequired

Marketplace destino.

{ "feniciaCategoryId": "cat-ropa-playeras", "marketplace": "walmart" }
200
{
  "found": true,
  "mapping": {
    "feniciaCategoryId": "cat-ropa-playeras",
    "marketplace": "walmart",
    "marketplaceCategoryId": "5438",
    "marketplaceCategoryName": "Shirts",
    "confidence": 0.95
  }
}
200Sin mapeo existente
{ "found": false }
400
{ "success": false, "error": "feniciaCategoryId and marketplace are required", "code": "MISSING_PARAMETER" }

Permiso requerido: products:read

Crea o actualiza el mapeo entre una categoría Fenicia y un marketplace

feniciaCategoryIdstringrequired

ID de la categoría Fenicia.

feniciaCategoryPathstring

Ruta legible de la categoría Fenicia.

marketplacestringrequired

Marketplace destino.

marketplaceCategoryIdstringrequired

ID de la categoría en el marketplace.

marketplaceCategoryNamestring

Nombre legible de la categoría en el marketplace.

mappingTypestring

Tipo de mapeo (por ejemplo, manual vs. generado por IA).

confidencenumber

Confianza del mapeo, si fue generado automáticamente.

sourcestring

Origen del mapeo.

attributeMappingsobject

Mapeo de atributos asociado.

{
  "feniciaCategoryId": "cat-ropa-playeras",
  "feniciaCategoryPath": "Ropa > Playeras",
  "marketplace": "walmart",
  "marketplaceCategoryId": "5438",
  "marketplaceCategoryName": "Shirts",
  "mappingType": "ai_inferred",
  "confidence": 0.95,
  "source": "ai",
  "attributeMappings": { "color": "COLOR_ATTR", "size": "SIZE_ATTR" }
}
400
{ "success": false, "error": "feniciaCategoryId, marketplace, and marketplaceCategoryId are required", "code": "MISSING_PARAMETER" }

Permiso requerido: products:manage

Registra el resultado de usar un mapeo (por ejemplo, tras exportar un producto con esa categoría) y devuelve sus métricas actualizadas

feniciaCategoryIdstringrequired

ID de la categoría Fenicia.

marketplacestringrequired

Marketplace.

successboolean

Si el uso del mapeo fue exitoso.

errorCodestring

Código de error, si `success` es `false`.

errorMessagestring

Mensaje de error.

{ "feniciaCategoryId": "cat-ropa-playeras", "marketplace": "walmart", "success": true }
200
{ "status": "active", "usageCount": 34, "successRate": 0.97 }
200Sin registro de uso previo
null

Permiso requerido: products:read

Lista mapeos pendientes de aprobación

marketplacestring

Filtra por marketplace.

limitnumber

Límite de resultados. Default 50.

200
{
  "success": true,
  "data": {
    "total": 2,
    "mappings": [
      {
        "feniciaCategoryId": "cat-ropa-playeras",
        "marketplace": "walmart",
        "marketplaceCategoryId": "5438",
        "marketplaceCategoryPath": "Shirts",
        "mappingType": "ai_inferred",
        "confidence": 0.82,
        "source": "ai",
        "status": "pending",
        "stats": { "usageCount": 6, "successRate": 0.83 }
      }
    ]
  }
}
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: settings:read

Aprueba o rechaza un mapeo pendiente

feniciaCategoryIdstringrequired

ID de la categoría Fenicia del mapeo.

marketplacestringrequired

Marketplace del mapeo.

approvedbooleanrequired

`true` para aprobar, `false` para rechazar.

rejectionReasonstring

Motivo del rechazo, cuando `approved` es `false`.

{ "feniciaCategoryId": "cat-ropa-playeras", "marketplace": "walmart", "approved": true }
200
{
  "success": true,
  "data": {
    "feniciaCategoryId": "cat-ropa-playeras",
    "marketplace": "walmart",
    "marketplaceCategoryId": "5438",
    "marketplaceCategoryPath": "Shirts",
    "mappingType": "ai_inferred",
    "confidence": 0.82,
    "source": "ai",
    "status": "validated",
    "stats": { "usageCount": 6, "successRate": 0.83 },
    "validatedAt": "2026-07-21T18:40:00.000Z",
    "validatedBy": "admin"
  }
}
400
{ "success": false, "error": "feniciaCategoryId, marketplace, and approved are required", "code": "MISSING_PARAMETER" }

Permiso requerido: settings:manage

Estadísticas agregadas de mapeos

marketplacestring

Restringe las estadísticas a un marketplace.

200
{
  "success": true,
  "data": {
    "service": {
      "version": "2.13.0",
      "description": "Bidirectional Fenicia ↔ Marketplace category mappings"
    },
    "stats": {
      "totalMappings": 634,
      "byStatus": { "pending": 40, "auto_approved": 210, "validated": 350, "flagged": 12, "rejected": 22 },
      "bySource": { "manual": 100, "ai": 480, "community": 0, "api": 40, "publication_feedback": 14 },
      "avgConfidence": 0.91,
      "avgSuccessRate": 0.96,
      "totalUsage": 5820
    }
  }
}
500
{ "success": false, "error": "Unknown error", "code": "INTERNAL_ERROR" }

Permiso requerido: settings:read

Resolución de atributos por IA (multi-marketplace)

Además de POST /categories/walmart/resolve-attributes (documentado arriba), existen dos variantes: una genérica multi-marketplace y una específica de MercadoLibre.

Resuelve, con IA, atributos requeridos por una categoría de cualquier marketplace soportado, a partir de una lista de requerimientos

requirementsarrayrequired

Lista de requerimientos de atributos a resolver.

productobjectrequired

Datos del producto; `product.title` es requerido.

channelTypestring

Tipo de canal/marketplace, como contexto adicional.

localestring

Idioma para la resolución.

{
  "requirements": [
    {
      "id": "MATERIAL_SUELA",
      "name": "Material de la suela",
      "type": "select",
      "required": true,
      "allowedValues": [{ "id": "GOMA", "name": "Goma" }, { "id": "CUERO", "name": "Cuero" }]
    }
  ],
  "product": {
    "title": "Tenis casuales para hombre",
    "brand": "Fenicia Basics",
    "attributes": [{ "name": "suela", "value": "Goma" }]
  },
  "channelType": "tiktok",
  "locale": "es"
}
200
{
  "success": true,
  "resolvedAttributes": [
    { "id": "MATERIAL_SUELA", "value": "Goma", "confidence": 0.98, "source": "exact_match" }
  ],
  "unresolvedAttributes": [],
  "processingTimeMs": 210
}
400
{ "code": "MISSING_PARAMETER", "message": "requirements array is required" }

Permiso requerido: products:read

Resuelve atributos requeridos por una categoría de MercadoLibre; los atributos de variante (talla/color) se derivan de las variantes reales del producto, no se adivinan con IA

requirementsarrayrequired

Lista de requerimientos de atributos.

productobjectrequired

Datos del producto; `product.title` es requerido.

categoryIdstringrequired

ID de la categoría de MercadoLibre.

categoryNamestring

Nombre de la categoría.

hasVariantsboolean

Si el producto tiene variantes.

variantAxesarray

Ejes de variante del producto (por ejemplo, talla, color).

{
  "product": {
    "title": "Tenis Nike Air Max",
    "brand": "Nike",
    "attributes": [{ "name": "material", "value": "Sintético" }]
  },
  "requirements": [
    { "id": "BRAND", "name": "Marca", "type": "text", "required": true, "sourceField": "brand" }
  ],
  "categoryId": "MLM1234",
  "categoryName": "Tenis",
  "hasVariants": true,
  "variantAxes": ["Talla", "Color"]
}
200
{
  "success": true,
  "resolvedAttributes": [
    { "attributeId": "BRAND", "value": "Nike", "valueType": "value_name", "confidence": 0.99, "source": "product_field" }
  ],
  "unresolvedAttributes": [],
  "variantAttributes": [
    {
      "attributeId": "TALLA",
      "name": "Talla",
      "reason": "allows_variations",
      "valueType": "value_id",
      "resolvedByVariant": [
        { "sku": "TENIS-001-28", "feniciaValue": "28", "mlValue": { "id": "28MX", "name": "28 MX" }, "confidence": 1, "matched": true }
      ]
    }
  ],
  "stats": {
    "totalAttributes": 2,
    "resolvedCount": 1,
    "variantCount": 1,
    "unresolvedCount": 0,
    "processingTimeMs": 380,
    "aiInferredCount": 0
  }
}
400
{ "code": "MISSING_PARAMETER", "message": "requirements array is required" }

Permiso requerido: products:read

variantAttributes: derivado de datos reales, no de IA

A diferencia del resto de los endpoints de resolución de atributos, la respuesta de este endpoint incluye un campo variantAttributes construido a partir de las opciones/variantes reales del producto (por ejemplo, SIZE/COLOR) — no es una inferencia de IA, e incluye resolvedByVariant[] con el valor ya emparejado por SKU. El resto de los atributos resueltos (resolvedAttributes[]) sí puede provenir del motor de IA (source: 'ai_inferred'), además de exact_match, alias_match, default o product_field.

Ejemplo — sugerir el código SAT de un producto

curl -X POST https://api.fenicia.io/categories/sat/suggest \
  -H "Authorization: Bearer fkapi_tu_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Camisa de algodón manga larga" }'

Errores

CódigoStatusDescripción
MISSING_PARAMETER400Falta un parámetro requerido (q, title, etc.).
not-found404Ruta desconocida. La respuesta incluye availableRoutes con el listado completo de rutas soportadas por este lambda.
auth:invalid_token401La API key es inválida, fue revocada, o no se pudo resolver el tenant.
auth:permission_denied403La API key no tiene el permiso requerido.

Consulta el catálogo completo de errores para el resto de los códigos posibles.

CORS: sin PUT/DELETE

Este dominio solo permite GET, POST y OPTIONS a nivel de CORS — no hay operaciones PUT/DELETE sobre /categories/* (coherente con que todas las rutas de escritura de este dominio son POST, nunca PUT/DELETE).

Siguientes pasos