Estos endpoints cubren el ciclo de vida de escritura de un producto: creación, actualización (parcial o completa) y borrado. El renombrado de SKU no tiene endpoint propio — se dispara implícitamente al actualizar. El borrado es permanente.
Permisos requeridos:products:create para crear, products:update para actualizar, products:delete para borrar.
Máximo 100 caracteres. Único por tenant (índice compuesto tenantId + sku).
title.value
string
Máximo 500 caracteres.
price
number
Mínimo 0.
currency
string
Código ISO 4217.
status
string
active, disabled o draft — ver la nota sobre el enum real abajo.
status real tiene 3 valores, no 5
El schema persistido (Mongoose) solo acepta active, disabled y draft, con default draft. Si tu integración proviene de otra fuente que asume los 5 valores del tipo TS público (active/disabled/inactive/draft/out_of_stock), ten cuidado: inactive y out_of_stock son rechazados al guardar.
El cuerpo acepta cualquier subconjunto de los campos del producto — no es necesario reenviar el objeto completo. Dos comportamientos especiales de la librería de validación:
compareAtPrice: null se interpreta como "limpiar el campo" de forma explícita, distinto de simplemente omitirlo.
Límites de tamaño en arreglos: variants.length ≤ 100, bindings.length ≤ 50.
También existe una variante legada:PUT /products (sin {id} en la ruta, con el SKU dentro del body). Mismo permiso y mismo comportamiento — se documenta aquí por completitud, pero usa PUT /products/{id} en integraciones nuevas.
No existe un endpoint dedicado para renombrar un SKU
Para cambiar el SKU de un producto, envía el nuevo valor en el campo sku del body de PUT /products/{id}. Si body.sku difiere del SKU almacenado, el lambda dispara internamente el rename en cascada — no hay una ruta separada como POST /products/{id}/rename.
El rename en cascada actualiza, en la misma operación: los registros de inventario asociados, inventory_tracks, las referencias desde BOM/bundle/modificadores que apunten al SKU viejo, y emite el evento ProductSkuChanged. Trátalo como una operación de mayor impacto que una actualización de campo simple — verifica que el nuevo SKU no colisione con uno existente (responderá 409 duplicate-sku si lo hace).
{ "code": "not-found", "message": "Product not found" }
Permiso requerido:products:delete
Hard delete irreversible — sin papelera, sin soft-delete
Este endpoint ejecuta un deleteOne directo sobre la colección de MongoDB. No hay papelera de reciclaje ni estado recuperable. Una vez borrado, el producto y su historial dejan de existir en la base de datos — no puedes restaurarlo desde la API.
Esto es distinto de poner status: 'disabled', que es un estado lógico reversible (el producto sigue existiendo, solo se oculta/desactiva). Si tu flujo necesita la posibilidad de "deshacer", usa PUT /products/{id} con {"status": "disabled"} en lugar de DELETE.
El producto no cumple las reglas de validación. Incluye fieldErrors[] con el detalle por campo.
duplicate-sku
409
Ya existe un producto con ese SKU en el tenant (al crear, o al renombrar hacia un SKU ocupado).
not-found
404
No existe un producto que resuelva el id/SKU indicado (en PUT, solo cuando el identificador es un _id que no resuelve; en DELETE, siempre que no exista).
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.