Inventario
La API de inventario permite gestionar el stock de productos en múltiples ubicaciones. Cannahub utiliza el sistema de inventario multi-ubicación de Medusa para trackear stock por club y calcular totales en gramos para productos de flor.
El inventario en Cannahub usa un multiplicador de peso para flores: una unidad de "Blue Dream 7g" representa 7 gramos de inventario total.
El modelo de Inventario
ProductLocationStock
Representa el stock de una variante en una ubicación específica.
- Name
productId- Type
- string
- Description
ID del producto padre.
- Name
variantId- Type
- string
- Description
ID de la variante específica.
- Name
inventoryItemId- Type
- string
- Description
ID del item de inventario en Medusa.
- Name
locationId- Type
- string
- Description
ID de la ubicación de stock.
- Name
locationName- Type
- string
- Description
Nombre legible de la ubicación.
- Name
quantity- Type
- number
- Description
Unidades físicas en stock.
- Name
reservedQuantity- Type
- number
- Description
Unidades reservadas por pedidos pendientes.
- Name
availableQuantity- Type
- number
- Description
Unidades disponibles para dispensación (quantity - reserved).
- Name
incomingQuantity- Type
- number
- Description
Unidades en tránsito/esperadas.
Interface ProductLocationStock
interface ProductLocationStock {
productId: string
variantId: string
inventoryItemId: string
locationId: string
locationName: string
quantity: number
reservedQuantity: number
availableQuantity: number
incomingQuantity: number
}
Ejemplo
{
"productId": "prod_01HQ8BD5G",
"variantId": "variant_01HQ_BD_7G",
"inventoryItemId": "iitem_01HQ_BD_7G",
"locationId": "sloc_high_up",
"locationName": "High Up - Dispensario",
"quantity": 50,
"reservedQuantity": 5,
"availableQuantity": 45,
"incomingQuantity": 0
}
InventoryLevel
Modelo raw de Medusa para niveles de inventario.
- Name
id- Type
- string
- Description
ID único del nivel de inventario.
- Name
inventoryItemId- Type
- string
- Description
ID del item de inventario asociado.
- Name
locationId- Type
- string
- Description
ID de la ubicación.
- Name
stockedQuantity- Type
- number
- Description
Cantidad total en stock.
- Name
reservedQuantity- Type
- number
- Description
Cantidad reservada.
- Name
incomingQuantity- Type
- number
- Description
Cantidad entrante.
Interface InventoryLevel
interface InventoryLevel {
id: string
inventoryItemId: string
locationId: string
stockedQuantity: number
reservedQuantity: number
incomingQuantity: number
availableQuantity: number
location?: StockLocation
metadata?: Record<string, unknown>
createdAt?: string
updatedAt?: string
}
Multiplicador de Inventario
Para productos de flor, el inventario se calcula multiplicando las unidades por el peso de la variante.
Lógica del Multiplicador
inventoryTotal = quantity × weight
Ejemplo
| Variante | Unidades | Peso | Total (gramos) |
|---|---|---|---|
| Blue Dream 1g | 100 | 1g | 100g |
| Blue Dream 3.5g | 50 | 3.5g | 175g |
| Blue Dream 7g | 20 | 7g | 140g |
| Total | 170 | - | 415g |
Cálculo de inventario
function calculateInventoryTotal(
variant: ProductVariant,
inventoryQuantity: number
): number {
// Obtener peso de metadata
const weight = variant.metadata?.weight
?? variant.metadata?.quantity
?? 1
// Multiplicar para obtener total en gramos
return inventoryQuantity * weight
}
// Uso
const variant = {
id: 'variant_bd_7g',
name: 'Blue Dream 7g',
metadata: { weight: 7 }
}
const total = calculateInventoryTotal(variant, 20)
// total = 140 (gramos)
Listar inventario
Este endpoint lista los items de inventario con sus niveles por ubicación.
Parámetros de Consulta
- Name
location_id- Type
- string
- Description
Filtrar por ubicación de stock.
- Name
search- Type
- string
- Description
Filtrar por SKU o titulo.
- Name
limit- Type
- number
- Description
Límite de resultados (default: 20).
- Name
offset- Type
- number
- Description
Offset para paginación.
Request
curl -G https://app.cannahub.tech/api/inventory \
-H "Authorization: Bearer {token}" \
-d location_id=sloc_high_up
Response
{
"items": [
{
"id": "iitem_01HQ_BD_7G",
"sku": "BD-7G-001",
"title": "Blue Dream 7g",
"stockedQuantity": 50,
"reservedQuantity": 5,
"availableQuantity": 45,
"locationLevels": [
{
"id": "ilevel_01HQ",
"locationId": "sloc_high_up",
"stockedQuantity": 50,
"reservedQuantity": 5,
"incomingQuantity": 0,
"availableQuantity": 45
}
]
}
],
"count": 45,
"offset": 0,
"limit": 20
}
Obtener inventario de variante
Obtiene el detalle de un item de inventario específico con todos sus niveles.
Request
curl https://app.cannahub.tech/api/inventory/iitem_01HQ_BD_7G \
-H "Authorization: Bearer {admin_token}"
Response
{
"item": {
"id": "iitem_01HQ_BD_7G",
"sku": "BD-7G-001",
"title": "Blue Dream 7g",
"requiresShipping": true,
"stockedQuantity": 250,
"reservedQuantity": 5,
"availableQuantity": 245,
"locationLevels": [
{
"id": "ilevel_01HQ",
"locationId": "sloc_high_up",
"stockedQuantity": 50,
"reservedQuantity": 5,
"incomingQuantity": 0,
"availableQuantity": 45
},
{
"id": "ilevel_02HQ",
"locationId": "sloc_deposito",
"stockedQuantity": 200,
"reservedQuantity": 0,
"incomingQuantity": 50,
"availableQuantity": 200
}
]
}
}
Actualizar nivel de inventario
Actualiza el nivel de stock en una ubicación específica.
Body
- Name
stockedQuantity- Type
- number
- Description
Nueva cantidad en stock.
- Name
incomingQuantity- Type
- number
- Description
Cantidad entrante esperada.
Request
curl -X PATCH https://app.cannahub.tech/api/inventory/levels \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"inventoryItemId": "iitem_01HQ_BD_7G",
"locationId": "sloc_high_up",
"stockedQuantity": 60
}'
Response
{
"level": {
"id": "ilevel_01HQ",
"locationId": "sloc_high_up",
"stockedQuantity": 60,
"reservedQuantity": 5,
"incomingQuantity": 0,
"availableQuantity": 55
}
}
Ajuste de inventario (incremento/decremento)
Para ajustes de inventario por dispensaciones, devoluciones, o correcciones.
Reservaciones
Las reservaciones son creadas automáticamente cuando se agrega un item al carrito y se liberan si el carrito expira o se cancela.
Flujo de reservación
// 1. Cliente agrega item al carrito
// → Se crea reservación automática
// reserved_quantity += ordered_quantity
// 2. Cliente completa la orden
// → Se confirma la reservación
// stocked_quantity -= ordered_quantity
// reserved_quantity -= ordered_quantity
// 3. Si el carrito expira/cancela
// → Se libera la reservación
// reserved_quantity -= ordered_quantity
Stock Locations (Filiales)
Las ubicaciones de stock (filiales) son fundamentales para el inventario multi-ubicacion. Para documentacion completa sobre gestion de filiales, consulta la API de Filiales.
La API de Filiales (/api/locations) proporciona endpoints CRUD completos para gestionar ubicaciones de stock.
BFF Route: Producto con Inventario
Endpoint BFF que retorna un producto con inventario agregado de todas las ubicaciones en una sola llamada.
Beneficio
Reduce el problema N+1 de consultar inventario por cada variante.
Request
curl https://app.cannahub.tech/api/products/prod_01HQ8BD5G/with-inventory \
-H "Authorization: Bearer {token}"
Response
{
"product": {
"id": "prod_01HQ8BD5G",
"name": "Blue Dream Indoor",
"variants": [
{
"id": "variant_bd_1g",
"name": "Blue Dream 1g",
"weight": 1,
"price": 350
},
{
"id": "variant_bd_7g",
"name": "Blue Dream 7g",
"weight": 7,
"price": 2100
}
]
},
"inventory": {
"variant_bd_1g": {
"quantity": 100,
"available": 95,
"reserved": 5,
"totalGrams": 100,
"byLocation": [
{
"locationId": "sloc_high_up",
"locationName": "High Up",
"quantity": 100,
"available": 95
}
]
},
"variant_bd_7g": {
"quantity": 50,
"available": 45,
"reserved": 5,
"totalGrams": 350,
"byLocation": [
{
"locationId": "sloc_high_up",
"locationName": "High Up",
"quantity": 50,
"available": 45
}
]
}
},
"totalInventoryGrams": 450
}
BFF Route: Actualización Batch
Permite actualizar inventario de múltiples variantes en una sola llamada. Esta ruta reduce N llamadas individuales a 1 sola llamada.
Problema que resuelve
Flujo actual (N calls):
Para 10 variantes:
1. POST /admin/inventory-items/:id1/location-levels/:loc
2. POST /admin/inventory-items/:id2/location-levels/:loc
3. POST /admin/inventory-items/:id3/location-levels/:loc
...10 llamadas secuenciales
Body
- Name
updates- Type
- array
- Description
Array de actualizaciones a aplicar.
- Name
variantId- Type
- string
- Description
ID de la variante a actualizar.
- Name
locationId- Type
- string
- Description
ID de la ubicación de stock.
- Name
quantity- Type
- number
- Description
Nueva cantidad en stock.
- Name
adjustment- Type
- number
- Description
Ajuste relativo (+/-) en lugar de cantidad absoluta.
- Name
reason- Type
- string
- Description
Razón del ajuste para auditoría.
- Name
validateStock- Type
- boolean
- Description
Si es
true, valida que haya stock suficiente para decrementos.
En producción cada update debe incluir además el inventoryItemId del item de inventario (obtenido con los endpoints de lookup de inventario). Los updates sin inventoryItemId se devuelven en results con status: "error". En modo mock el inventoryItemId no es necesario.
Response
- Name
success- Type
- boolean
- Description
Si todas las actualizaciones fueron exitosas.
- Name
updated- Type
- number
- Description
Número de items actualizados exitosamente.
- Name
failed- Type
- number
- Description
Número de items que fallaron.
- Name
results- Type
- array
- Description
Detalle de cada actualización.
Request
curl -X POST https://app.cannahub.tech/api/inventory/batch-update \
-H "Authorization: Bearer {admin_token}" \
-H "Content-Type: application/json" \
-d '{
"updates": [
{
"variantId": "variant_bd_1g",
"locationId": "sloc_high_up",
"quantity": 150
},
{
"variantId": "variant_bd_7g",
"locationId": "sloc_high_up",
"quantity": 75
}
]
}'
Response
{
"success": true,
"updated": 2,
"failed": 0,
"results": [
{
"variantId": "variant_bd_1g",
"locationId": "sloc_high_up",
"previousQuantity": 100,
"newQuantity": 150,
"totalGrams": 150,
"status": "success"
},
{
"variantId": "variant_bd_7g",
"locationId": "sloc_high_up",
"previousQuantity": 50,
"newQuantity": 75,
"totalGrams": 525,
"status": "success"
}
],
"summary": {
"totalUnitsUpdated": 75,
"totalGramsUpdated": 525
}
}
Response con error parcial
{
"success": false,
"updated": 1,
"failed": 1,
"results": [
{
"variantId": "variant_bd_1g",
"status": "success",
"previousQuantity": 100,
"newQuantity": 150
},
{
"variantId": "variant_invalid",
"status": "error",
"error": "Variant not found"
}
]
}
Comparación de rendimiento
| Métrica | Sin BFF (10 items) | Con BFF | Mejora |
|---|---|---|---|
| Llamadas API | 10 | 1 | -90% |
| Latencia típica | ~2000ms | ~300ms | -85% |
| Manejo de errores | Manual por item | Centralizado | Simplificado |
| Auditoría | N registros separados | 1 batch log | Trazabilidad |
BFF Route: Stock Location Setup
Esta ruta crea una ubicación de stock completa con todo su fulfillment chain en una sola llamada. Normalmente esto requiere 7+ llamadas secuenciales a Medusa.
Problema que resuelve
Flujo actual (7+ calls secuenciales):
1. POST /admin/stock-locations → Crear ubicación
2. POST /admin/fulfillment-sets → Crear fulfillment set
3. POST /admin/service-zones → Crear service zone
4. POST /admin/geo-zones → Crear geo zone
5. POST /admin/shipping-options → Crear opción de envío
6. POST /admin/shipping-options → Crear opción de pickup
7. POST /admin/stock-locations/:id/sales-channels
→ Asociar sales channel
Request Body
- Name
name- Type
- string
- Description
Nombre de la ubicación.
- Name
address- Type
- object
- Description
Dirección física de la ubicación.
- Name
address_1- Type
- string
- Description
Dirección principal.
- Name
city- Type
- string
- Description
Ciudad.
- Name
province- Type
- string
- Description
Provincia/Estado.
- Name
postal_code- Type
- string
- Description
Código postal.
- Name
country_code- Type
- string
- Description
Código de país (ej: "AR").
- Name
enableShipping- Type
- boolean
- Description
Habilitar envíos desde esta ubicación (default: false).
- Name
enablePickup- Type
- boolean
- Description
Habilitar retiro en esta ubicación (default: true).
- Name
salesChannelId- Type
- string
- Description
ID del canal de ventas a asociar.
- Name
metadata- Type
- object
- Description
Datos adicionales (club, tipo, horarios, etc).
Response
- Name
stockLocation- Type
- StockLocation
- Description
La ubicación creada.
- Name
fulfillmentSet- Type
- FulfillmentSet
- Description
El fulfillment set asociado.
- Name
serviceZone- Type
- ServiceZone
- Description
La service zone creada.
- Name
shippingOptions- Type
- array
- Description
Las opciones de envío configuradas.
Request
curl -X POST https://app.cannahub.tech/api/stock-locations/setup \
-H "Authorization: Bearer {admin_token}" \
-H "Content-Type: application/json" \
-d '{
"name": "High Up - Dispensario Palermo",
"address": {
"address_1": "Av. Santa Fe 3200",
"city": "Buenos Aires",
"province": "CABA",
"postal_code": "C1425",
"country_code": "AR"
},
"enableShipping": false,
"enablePickup": true,
"salesChannelId": "sc_01KBCZXJCPVWX8REW8880R45SW",
"metadata": {
"club": "high-up",
"type": "dispensary",
"schedule": {
"monday": "10:00-20:00",
"tuesday": "10:00-20:00",
"wednesday": "10:00-20:00",
"thursday": "10:00-20:00",
"friday": "10:00-20:00",
"saturday": "12:00-18:00",
"sunday": "closed"
}
}
}'
Response
{
"stockLocation": {
"id": "sloc_01KDPALERMO",
"name": "High Up - Dispensario Palermo",
"address": {
"address_1": "Av. Santa Fe 3200",
"city": "Buenos Aires",
"province": "CABA",
"postal_code": "C1425",
"country_code": "AR"
},
"metadata": {
"club": "high-up",
"type": "dispensary"
}
},
"fulfillmentSet": {
"id": "fset_01KDPALERMO",
"name": "High Up - Dispensario Palermo Fulfillment",
"type": "pickup"
},
"serviceZone": {
"id": "szone_01KDPALERMO",
"name": "High Up Palermo Zone",
"geo_zones": [
{
"id": "gzone_01KDPALERMO",
"type": "country",
"country_code": "AR"
}
]
},
"shippingOptions": [
{
"id": "so_01KDPALERMO_PICKUP",
"name": "Retiro en Dispensario Palermo",
"price_type": "flat",
"amount": 0,
"is_return": false,
"metadata": {
"type": "pickup",
"locationId": "sloc_01KDPALERMO"
}
}
],
"summary": {
"totalApiCalls": 7,
"savedCalls": 6,
"executionTimeMs": 450
}
}
Flujo interno del BFF
Comparación de rendimiento
| Métrica | Sin BFF | Con BFF | Mejora |
|---|---|---|---|
| Llamadas API | 7+ | 1 | -86% |
| Latencia típica | ~1400ms | ~450ms | -68% |
| Complejidad cliente | Alta (secuencial) | Baja (1 request) | Simplificado |
| Rollback en error | Manual | Automático | Transaccional |
Mapeo Medusa
La API BFF transforma las respuestas de Medusa de snake_case a camelCase:
| UI (camelCase) | Medusa (snake_case) |
|---|---|
inventoryItemId | inventory_item_id |
locationId | location_id |
stockedQuantity | stocked_quantity |
reservedQuantity | reserved_quantity |
incomingQuantity | incoming_quantity |
availableQuantity | available_quantity |
requiresShipping | requires_shipping |
originCountry | origin_country |
hsCode | hs_code |
midCode | mid_code |
createdAt | created_at |
updatedAt | updated_at |
locationLevels | location_levels |
Diagrama de Flujo de Inventario
Origen de Cosecha (Seed-to-Sale)
Al editar stock, los modales permiten seleccionar una cosecha como origen para trazabilidad. Esto habilita el flujo completo de seed-to-sale.
Funcionalidad
- Selector de Cosecha: Combobox que filtra cosechas por la genética del producto
- Solo STOCKED: Solo muestra cosechas con estado
STOCKED(listas para dispensar) - Peso Disponible: Muestra los gramos disponibles de cada cosecha
- Warning de Exceso: Alerta si el stock a agregar excede el peso disponible de la cosecha
Modales Actualizados
EditProductStockModal- Stock por ubicaciónEditStockDialog- Stock multi-ubicación con acordeónEditStockModal- Nivel de inventario individual
La persistencia del origen de cosecha está pendiente de implementación en backend.
Los modales incluyen // TODO comments para la integración futura.
HarvestsCombobox Props
type Props = {
value: string | undefined
setValue: (value: string | undefined) => void
strainId?: string // Filtra por genética
setHarvest?: (harvest: Harvest | undefined) => void
disabled?: boolean
placeholder?: string
}
StockUpdateWithSource Type
// src/api/custom/stock.ts
type StockUpdateWithSource = {
inventoryItemId: string
locationId: string
quantity: number
sourceHarvestId?: string // Trazabilidad seed-to-sale
}
Uso en Modal
// Estado para selección de cosecha
const [selectedHarvestId, setSelectedHarvestId] =
useState<string | undefined>()
const [selectedHarvest, setSelectedHarvest] =
useState<Harvest | undefined>()
// Warning cuando stock > disponible
const harvestWarning = useMemo(() => {
if (!selectedHarvest) return null
const available = selectedHarvest.trimmedWeight || 0
const stockChange = newQty - originalQty
if (stockChange > available) {
return { change: stockChange, available }
}
return null
}, [selectedHarvest, formValues])
Flujo de Trazabilidad
Traducciones Agregadas
| Clave | ES | EN | DE |
|---|---|---|---|
sourceHarvest | Cosecha origen | Source Harvest | Quell-Ernte |
selectHarvest | Seleccionar cosecha a descontar | Select harvest to discount from | Ernte zum Abzug auswählen |
availableFromHarvest | Disponible de cosecha | Available from harvest | Verfügbar von Ernte |
harvestExceededWarning | La cantidad supera el peso disponible | Stock quantity exceeds harvest available | Bestandsmenge übersteigt verfügbares Erntegewicht |
Niveles de inventario
Obtiene los niveles de inventario para un item específico en todas las ubicaciones.
Parámetros de Consulta
- Name
inventory_item_id- Type
- string
- Description
ID del item de inventario del cual obtener niveles.
Request
curl -G https://app.cannahub.tech/api/inventory/levels \
-H "Authorization: Bearer {token}" \
-d inventory_item_id=iitem_01HQ_BD_7G
Response
{
"levels": [
{
"id": "ilevel_01HQ",
"inventoryItemId": "iitem_01HQ_BD_7G",
"locationId": "sloc_high_up",
"stockedQuantity": 50,
"reservedQuantity": 5,
"incomingQuantity": 0,
"availableQuantity": 45
},
{
"id": "ilevel_02HQ",
"inventoryItemId": "iitem_01HQ_BD_7G",
"locationId": "sloc_deposito",
"stockedQuantity": 200,
"reservedQuantity": 0,
"incomingQuantity": 50,
"availableQuantity": 200
}
]
}
Crear nivel de inventario
Crea un nuevo nivel de inventario para un item en una ubicación específica.
Body
- Name
inventory_item_id- Type
- string
- Description
ID del item de inventario.
- Name
location_id- Type
- string
- Description
ID de la ubicación de stock.
- Name
stocked_quantity- Type
- number
- Description
Cantidad inicial en stock (default: 0).
Request
curl -X POST https://app.cannahub.tech/api/inventory/levels \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"inventory_item_id": "iitem_01HQ_BD_7G",
"location_id": "sloc_high_up",
"stocked_quantity": 100
}'
Response
{
"level": {
"id": "ilevel_03HQ",
"inventoryItemId": "iitem_01HQ_BD_7G",
"locationId": "sloc_high_up",
"stockedQuantity": 100,
"reservedQuantity": 0,
"incomingQuantity": 0,
"availableQuantity": 100
}
}
Actualizar nivel de inventario
Actualiza un nivel de inventario existente.
Body
- Name
inventory_item_id- Type
- string
- Description
ID del item de inventario.
- Name
location_id- Type
- string
- Description
ID de la ubicación de stock.
- Name
stocked_quantity- Type
- number
- Description
Nueva cantidad en stock.
- Name
incoming_quantity- Type
- number
- Description
Nueva cantidad entrante esperada.
Request
curl -X PATCH https://app.cannahub.tech/api/inventory/levels \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"inventory_item_id": "iitem_01HQ_BD_7G",
"location_id": "sloc_high_up",
"stocked_quantity": 60,
"incoming_quantity": 0
}'
Response
{
"level": {
"id": "ilevel_01HQ",
"inventoryItemId": "iitem_01HQ_BD_7G",
"locationId": "sloc_high_up",
"stockedQuantity": 60,
"reservedQuantity": 5,
"incomingQuantity": 0,
"availableQuantity": 55
}
}
Eliminar nivel de inventario
Elimina un nivel de inventario de una ubicación. Esto desvincula el item de inventario de dicha ubicación.
Parámetros de Consulta
- Name
inventory_item_id- Type
- string
- Description
ID del item de inventario.
- Name
location_id- Type
- string
- Description
ID de la ubicación de stock a desvincular.
Request
curl -X DELETE "https://app.cannahub.tech/api/inventory/levels?inventory_item_id=iitem_01HQ_BD_7G&location_id=sloc_high_up" \
-H "Authorization: Bearer {token}"
Response
{
"success": true,
"deleted": {
"inventoryItemId": "iitem_01HQ_BD_7G",
"locationId": "sloc_high_up"
}
}
Listar ubicaciones de stock
Lista todas las ubicaciones de stock (filiales) disponibles.
Parámetros de Consulta
- Name
include_sales_channels- Type
- boolean
- Description
Si es
true, incluye los canales de venta asociados a cada ubicación.
Request
curl -G https://app.cannahub.tech/api/inventory/locations \
-H "Authorization: Bearer {token}" \
-d include_sales_channels=true
Response
{
"stock_locations": [
{
"id": "sloc_high_up",
"name": "High Up - Dispensario",
"address": {
"address_1": "Av. Santa Fe 3200",
"city": "Buenos Aires",
"province": "CABA",
"country_code": "AR"
},
"metadata": {
"club": "high-up",
"type": "dispensary"
},
"sales_channels": [
{
"id": "sc_01KBCZXJCPVWX8REW8880R45SW",
"name": "High Up Store"
}
]
},
{
"id": "sloc_deposito",
"name": "Depósito Central",
"address": {
"address_1": "Calle Industria 500",
"city": "Buenos Aires",
"province": "CABA",
"country_code": "AR"
},
"metadata": {
"type": "warehouse"
},
"sales_channels": []
}
]
}
Crear ubicación de stock
Crea una nueva ubicación de stock (filial).
Body
- Name
name- Type
- string
- Description
Nombre de la ubicación.
- Name
address- Type
- object
- Description
Dirección física de la ubicación.
- Name
address_1- Type
- string
- Description
Dirección principal.
- Name
city- Type
- string
- Description
Ciudad.
- Name
province- Type
- string
- Description
Provincia/Estado.
- Name
postal_code- Type
- string
- Description
Código postal.
- Name
country_code- Type
- string
- Description
Código de país (ej: "AR").
- Name
metadata- Type
- object
- Description
Datos adicionales (club, tipo, horarios, etc).
Request
curl -X POST https://app.cannahub.tech/api/inventory/locations \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Nuevo Dispensario Belgrano",
"address": {
"address_1": "Av. Cabildo 1500",
"city": "Buenos Aires",
"province": "CABA",
"postal_code": "C1426",
"country_code": "AR"
},
"metadata": {
"club": "high-up",
"type": "dispensary"
}
}'
Response
{
"stock_location": {
"id": "sloc_01KDBELGRANO",
"name": "Nuevo Dispensario Belgrano",
"address": {
"address_1": "Av. Cabildo 1500",
"city": "Buenos Aires",
"province": "CABA",
"postal_code": "C1426",
"country_code": "AR"
},
"metadata": {
"club": "high-up",
"type": "dispensary"
},
"created_at": "2026-05-09T10:00:00.000Z",
"updated_at": "2026-05-09T10:00:00.000Z"
}
}
Actualizar stock
Actualiza el stock de un item en una ubicación específica. Si no existe un nivel de inventario para esa combinación, lo crea automáticamente.
Body
- Name
inventory_item_id- Type
- string
- Description
ID del item de inventario.
- Name
location_id- Type
- string
- Description
ID de la ubicación de stock.
- Name
stocked_quantity- Type
- number
- Description
Nueva cantidad total en stock.
Request
curl -X PATCH https://app.cannahub.tech/api/inventory/stock \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"inventory_item_id": "iitem_01HQ_BD_7G",
"location_id": "sloc_high_up",
"stocked_quantity": 75
}'
Response
{
"level": {
"id": "ilevel_01HQ",
"inventoryItemId": "iitem_01HQ_BD_7G",
"locationId": "sloc_high_up",
"stockedQuantity": 75,
"reservedQuantity": 5,
"incomingQuantity": 0,
"availableQuantity": 70
},
"created": false
}
Response (nivel creado)
{
"level": {
"id": "ilevel_04HQ",
"inventoryItemId": "iitem_01HQ_BD_7G",
"locationId": "sloc_nuevo",
"stockedQuantity": 75,
"reservedQuantity": 0,
"incomingQuantity": 0,
"availableQuantity": 75
},
"created": true
}
Habilitar inventario para variante
Habilita la gestión de inventario para una variante de producto. Este endpoint ejecuta un proceso de tres pasos:
- Actualiza el flag
manage_inventoryde la variante atrue - Crea un inventory item asociado a la variante
- Vincula el inventory item con la variante
Body
- Name
variant_id- Type
- string
- Description
ID de la variante de producto para la cual habilitar inventario.
Request
curl -X POST https://app.cannahub.tech/api/inventory/enable-for-variant \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"variant_id": "variant_bd_7g"
}'
Response
{
"success": true,
"variant_id": "variant_bd_7g",
"inventory_item": {
"id": "iitem_01NEW_BD_7G",
"sku": null,
"requires_shipping": true,
"created_at": "2026-05-09T10:00:00.000Z"
},
"steps": {
"variant_updated": true,
"inventory_item_created": true,
"inventory_item_linked": true
}
}