Variantes y media

Esta página cubre los dos únicos endpoints con superficie propia sobre variantes y media de un producto: la lectura/actualización de una variante existente y la subida de imágenes vía URL prefirmada. También documenta, explícitamente, qué queda fuera de esta superficie — porque es más de lo que asumirías.

Variantes

Resumen de variantes y opciones

Devuelve la estructura de variantes y opciones de un producto

skustringrequired

SKU del producto padre.

200
{
  "sku": "CAM-ROJO-M",
  "variants": [
    {
      "id": "65f3a1b2c4d5e6f7a8b9c0f1",
      "sku": "CAM-ROJO-M-CH",
      "title": { "value": "Camisa Roja - Chica" },
      "price": 499.00,
      "position": 0,
      "options": [{ "id": "opt-talla", "name": "Talla", "value": "CH" }]
    }
  ],
  "options": [{ "id": "opt-talla", "name": "Talla", "values": ["CH", "M", "G"] }],
  "hasVariants": true,
  "hasOptions": true
}
404
{ "code": "not-found", "message": "Product CAM-ROJO-M not found" }

Permiso requerido: products:read

Este endpoint ya se documenta con su ejemplo de respuesta completo en Consultar un producto — devuelve {sku, variants[], options[], hasVariants, hasOptions}.

Actualizar campos de una variante existente

Actualiza uno o más campos de una variante existente

productSkustringrequired

SKU del producto padre.

variantSkustringrequired

SKU de la variante a actualizar.

{ "price": 549.00 }
200
{
  "message": "Variant updated",
  "productSku": "CAM-ROJO-M",
  "variantSku": "CAM-ROJO-M-CH",
  "variant": {
    "id": "65f3a1b2c4d5e6f7a8b9c0f1",
    "sku": "CAM-ROJO-M-CH",
    "price": 549.00,
    "position": 0,
    "taxable": true,
    "options": [{ "id": "opt-talla", "name": "Talla", "value": "CH" }]
  }
}
404
{ "code": "not-found", "message": "Product 'CAM-ROJO-M' or variant 'CAM-ROJO-M-CH' not found" }

Permiso requerido: products:update

El cuerpo del request es un objeto plano { [campo]: valor } con cualquier campo válido de variante (price, title, position, taxable, shipping, minAlertStock, sellIfOutOfStock, countryOfOrigin, etc.).

curl -X PUT https://api.fenicia.io/products/CAM-ROJO-M/variants/CAM-ROJO-M-CH \
  -H "Authorization: Bearer fkapi_tu_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "price": 549.00 }'

compareAtPrice NO se valida a nivel variante

A nivel producto, compareAtPrice debe ser mayor que price o el guardado falla. Esa misma regla no se aplica al compareAtPrice de una variante individual — puedes guardar una variante con un compareAtPrice menor o igual a su price sin que el request falle.

No existe crear/borrar variante — solo actualizar una existente

Este endpoint actualiza campos de una variante que ya existe. No hay un POST para crear una variante nueva ni un DELETE para eliminar una. La estructura completa del arreglo variants[] (agregar, quitar, reordenar variantes) se gestiona reenviando el arreglo completo dentro del payload de PUT /products/{id}.

Media

Subir una imagen

Genera una URL prefirmada de S3 para subir una imagen de producto

contentTypestringrequired

MIME type del archivo. Debe estar en la lista de tipos de imagen permitidos.

filenamestringrequired

Nombre del archivo.

sizenumber

Tamaño del archivo en bytes.

{ "contentType": "image/jpeg", "filename": "cam-rojo-m-1.jpg" }
200
{
  "uploadUrl": "https://fenicia-media-uploads.s3.amazonaws.com/...",
  "s3Key": "products/65f2.../cam-rojo-m-1.jpg",
  "publicUrl": "https://cdn.fenicia.io/img/cam-rojo-m-1.jpg",
  "expiresIn": 300
}
400
{
  "code": "bad-request/invalid-content-type",
  "message": "Content type \"application/pdf\" is not allowed. Allowed: JPEG, PNG, GIF, WEBP, MP4, WebM, MOV",
  "parameter": "contentType"
}

Permiso requerido: products:update

Este endpoint no sube el archivo — devuelve una URL prefirmada de S3 (uploadUrl) a la que subes el binario directamente vía PUT desde tu cliente, y una publicUrl que es la que vas a persistir en el media[] del producto.

# 1. Solicita la URL prefirmada
curl -X POST https://api.fenicia.io/products/media/upload \
  -H "Authorization: Bearer fkapi_tu_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "contentType": "image/jpeg", "filename": "cam-rojo-m-1.jpg" }'
 
# 2. Sube el binario directamente a la uploadUrl devuelta
curl -X PUT "https://fenicia-media-uploads.s3.amazonaws.com/..." \
  -H "Content-Type: image/jpeg" \
  --data-binary @cam-rojo-m-1.jpg

Después de subir el binario, agrega la entrada al arreglo media[] del producto con publicUrl como src, vía PUT /products/{id}:

{
  "media": [
    {
      "id": "m2",
      "src": "https://cdn.fenicia.io/img/cam-rojo-m-1.jpg",
      "type": "image",
      "position": 1,
      "alt": { "value": "Camisa roja, vista frontal" }
    }
  ]
}

No existe endpoint para borrar ni reordenar media

No hay una ruta dedicada para eliminar una imagen o cambiar su orden. El código fuente del lambda tiene comentarios TODO explícitos confirmando que soportar eso está pendiente. Para borrar, reordenar, o modificar cualquier entrada de media[], reenvía el arreglo media[] completo (con la entrada quitada, reordenada o modificada) dentro del payload de PUT /products/{id}.

Limitaciones conocidas: qué solo se gestiona por PUT completo

Varias partes del modelo de producto no tienen endpoint propio de lectura/escritura granular — se gestionan exclusivamente enviando el producto completo (o el subconjunto de campos relevante) a PUT /products/{id}. Esto está confirmado por comentarios TODO explícitos en el código fuente del lambda, no es una omisión de esta documentación:

ÁreaCómo se leeCómo se escribe
Atributos / custom fields (attributes[])Como parte del producto completoReenviando attributes[] completo vía PUT /products/{id}
SEO (seo.metaTitle, metaDescription, slug)?extend=seo en GET /products/{id}Reenviando seo vía PUT /products/{id} — no existe /products/{sku}/seo
Price schemas (priceSchemas[], precios por segmento/canal)Como parte del producto completoReenviando priceSchemas[] completo vía PUT /products/{id}
Media — crear, borrar, reordenarComo parte del producto completoReenviando media[] completo vía PUT /products/{id} (subir el binario sí tiene endpoint propio, ver arriba)

bundleConfig sigue el mismo patrón

No existe una entidad "bundle" con endpoints propios en la API pública. bundleConfig (los componentes de un producto tipo bundle) es un sub-shape más del Product, gestionado también dentro del payload completo de PUT /products/{id} — no hay una ruta como /products/{sku}/bundle. El único mecanismo de composición producto-de-productos con endpoints propios es BOM (bill of materials), orientado a manufactura/consumo, no a "kits de venta".

Errores

CódigoStatusDescripción
not-found404No existe el producto o la variante indicados.
bad-request400El body de la actualización de variante viene vacío o es inválido.
bad-request/missing-content-type / bad-request/missing-filename400contentType/filename faltantes al solicitar la URL de subida.
bad-request/invalid-media400contentType/size no pasan la validación del archivo (por ejemplo, tamaño excede el máximo permitido).
bad-request/invalid-content-type400contentType no está en la lista de tipos permitidos (JPEG, PNG, GIF, WEBP, MP4, WebM, MOV).
internal-error/media-upload500Error interno generando la URL prefirmada.

Los códigos de autenticación (token inválido, permiso faltante) son los mismos en toda la plataforma — consulta el catálogo completo de errores.

Siguientes pasos