All endpoints require JWT authentication via Authorization: Bearer <token> header.
Get All Products
GET /api/admin/inventory
Fetch all products with inventory data
Authentication
Required. Validated via verifyAdminToken(req) helper from auth-helper.js:3-18.
Response
Returns an array of product objects ordered by name and variant.
Variant name (e.g., “100g”, “Verde”)
Product visibility status
Weight in kg (default: 0.2)
Width in cm (default: 10)
Height in cm (default: 10)
Length in cm (default: 10)
Implementation
From inventory.js:14-20:
const products = await prisma.product.findMany({
orderBy: [
{ name: 'asc' },
{ variantName: 'asc' } // Ensure variants group nicely
]
});
return res.status(200).json(products);
Example Response
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"sku": "KAIU-LAV-100",
"name": "Jabón Natural de Lavanda",
"slug": "jabon-natural-de-lavanda-kaiu-lav-100",
"description": "Jabón artesanal con aceites esenciales de lavanda",
"variantName": "100g",
"category": "Jabones",
"price": 29900,
"stock": 45,
"isActive": true,
"images": [
"https://cdn.kaiucol.com/products/jabon-lavanda-100g.jpg"
],
"benefits": "Hidratante, relajante, aroma natural",
"weight": 0.15,
"width": 8,
"height": 3,
"length": 12,
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-03-01T14:30:00Z"
}
]
Create Product
POST /api/admin/inventory
Add a new product to the catalog
Request Body
Price in COP (Colombian Pesos)
Unique SKU. Auto-generated if not provided: KAIU-{timestamp}
Product description (default: empty string)
Variant identifier (e.g., “100g”, “Verde”, “Talla M”)
Product category (default: “Otros”)
Initial stock quantity (default: 0)
Product active status (default: true)
Array of image URLs (default: empty array)
Weight in kg (default: 0.2)
Width in cm (default: 10)
Height in cm (default: 10)
Length in cm (default: 10)
Implementation Details
From inventory.js:36-37:
const safeSku = sku || `KAIU-${Date.now().toString(36).toUpperCase()}`;
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-') + '-' + safeSku.toLowerCase();
Auto-generated Fields:
sku: Generated from timestamp if not provided
slug: Created from name + SKU for SEO-friendly URLs
Example Request
const response = await fetch('https://api.kaiucol.com/api/admin/inventory', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
},
body: JSON.stringify({
name: 'Shampoo Sólido de Romero',
description: 'Shampoo sólido con extracto de romero para cabello graso',
variantName: '80g',
category: 'Cuidado Capilar',
price: 34900,
stock: 30,
isActive: true,
weight: 0.08,
images: ['https://cdn.kaiucol.com/products/shampoo-romero.jpg'],
benefits: 'Controla la grasa, estimula el crecimiento'
})
});
Example Response
{
"success": true,
"product": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"sku": "KAIU-LXYZ1234",
"name": "Shampoo Sólido de Romero",
"slug": "shampoo-solido-de-romero-kaiu-lxyz1234",
"description": "Shampoo sólido con extracto de romero para cabello graso",
"variantName": "80g",
"category": "Cuidado Capilar",
"price": 34900,
"stock": 30,
"isActive": true,
"weight": 0.08,
"createdAt": "2026-03-04T15:20:00Z",
"updatedAt": "2026-03-04T15:20:00Z"
}
}
Update Product
PUT /api/admin/inventory
Update existing product properties
Request Body
Object containing fields to update. Only provided fields will be modified.Show Allowed Update Fields
price (number)
stock (number)
isActive (boolean)
name (string)
description (string)
category (string)
variantName (string)
benefits (string)
weight (number)
width (number)
height (number)
length (number)
images (array)
Implementation
From inventory.js:76-91:
// Allowed fields to update
const { price, stock, isActive, name, description, category,
variantName, benefits, weight, width, height, length, images } = updates;
const dataToUpdate = {};
if (typeof price !== 'undefined') dataToUpdate.price = Number(price);
if (typeof stock !== 'undefined') dataToUpdate.stock = Number(stock);
if (typeof isActive !== 'undefined') dataToUpdate.isActive = Boolean(isActive);
// ... (other fields)
const updatedProduct = await prisma.product.update({
where: { sku: sku },
data: dataToUpdate
});
Partial Updates: Only fields included in the updates object are modified. Omitted fields remain unchanged.
Example Request
// Update stock and price
await fetch('https://api.kaiucol.com/api/admin/inventory', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer <token>'
},
body: JSON.stringify({
sku: 'KAIU-LAV-100',
updates: {
stock: 60,
price: 32900,
isActive: true
}
})
});
Example Response
{
"success": true,
"product": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"sku": "KAIU-LAV-100",
"name": "Jabón Natural de Lavanda",
"price": 32900,
"stock": 60,
"isActive": true,
"updatedAt": "2026-03-04T16:45:00Z"
}
}
Common Use Cases
Bulk Stock Update
const products = [
{ sku: 'KAIU-LAV-100', stock: 50 },
{ sku: 'KAIU-ROM-80', stock: 30 },
{ sku: 'KAIU-MAN-120', stock: 25 }
];
for (const product of products) {
await fetch('https://api.kaiucol.com/api/admin/inventory', {
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
sku: product.sku,
updates: { stock: product.stock }
})
});
}
Create Product Variant
// Create new variant of existing product
await fetch('https://api.kaiucol.com/api/admin/inventory', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Jabón Natural de Lavanda',
variantName: '200g', // New size
category: 'Jabones',
price: 49900,
stock: 20,
weight: 0.2,
images: ['https://cdn.kaiucol.com/products/jabon-lavanda-200g.jpg']
})
});
Products with the same name but different variantName are displayed together in the admin interface and grouped by the orderBy clause.