Inventario
Los endpoints de inventario te permiten ajustar el stock de tus bodegas, mover existencias entre ellas y consultar el kardex (movimientos históricos de cada variante de producto).
La URL base de producción es https://api-pos.zelta.dev/public/v1 y todas las rutas se expresan relativas a ella. Todas las peticiones deben hacerse sobre HTTPS e incluir tu API key. Consulta para los detalles.
INFO
En los ítems de ajustes y transferencias, los productos se direccionan únicamente por referenceId (tu identificador externo). No se aceptan id interno, SKU ni código de barras. Asegúrate de haber asignado un referenceId a cada variante desde tu integración.
Ajustes de inventario
Un ajuste registra entradas (in) o salidas (out) de stock en una bodega. Úsalo para correcciones de conteo físico, mermas, mercancía dañada o ingresos manuales que no provienen de una compra.
WARNING
El cuerpo de la petición usa los valores in y out en cada ítem, pero la respuesta devuelve incoming y outgoing respectivamente. Téngalo en cuenta al mapear los datos.
Crear un ajuste
POST /inventory-adjustments| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
warehouseId | string (cuid2) | No | Bodega a ajustar. Por defecto, la bodega de la sucursal asociada a la API key. |
reason | string (≤255) | No | Motivo del ajuste. |
items | array | Sí | Mínimo un ítem. |
items[].referenceId | string | Sí | Identificador externo de la variante. |
items[].type | string | Sí | in (entrada) u out (salida). |
items[].quantity | number (>0) | Sí | Cantidad a ajustar. |
items[].notes | string (≤500) | No | Nota por línea. |
curl -X POST "https://api-pos.zelta.dev/public/v1/inventory-adjustments" \
-H "Authorization: Bearer zpk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"reason": "Ajuste por conteo físico de enero",
"items": [
{ "referenceId": "SKU-1001", "type": "in", "quantity": 12, "notes": "Diferencia de inventario" },
{ "referenceId": "SKU-2050", "type": "out", "quantity": 3 }
]
}'Ejemplo JS
const res = await fetch('https://api-pos.zelta.dev/public/v1/inventory-adjustments', {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.ZELTA_POS_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
reason: 'Ajuste por conteo físico de enero',
items: [
{ referenceId: 'SKU-1001', type: 'in', quantity: 12, notes: 'Diferencia de inventario' },
{ referenceId: 'SKU-2050', type: 'out', quantity: 3 }
]
})
});
const data = await res.json();Ejemplo Py
import requests
res = requests.post(
'https://api-pos.zelta.dev/public/v1/inventory-adjustments',
headers={'Authorization': 'Bearer zpk_live_xxx', 'Content-Type': 'application/json'},
json={
'reason': 'Ajuste por conteo físico de enero',
'items': [
{ 'referenceId': 'SKU-1001', 'type': 'in', 'quantity': 12, 'notes': 'Diferencia de inventario' },
{ 'referenceId': 'SKU-2050', 'type': 'out', 'quantity': 3 }
]
}
)
data = res.json()Respuesta 201 Created:
{
"id": "kx7p2m9q3v8r1n6t4w0y5z2a",
"number": "ADJ-000142",
"warehouseId": "wh3b8n5k2j7h9g4f1d6s0a8q",
"status": "applied",
"reason": "Ajuste por conteo físico de enero",
"notes": null,
"items": [
{
"productVariantId": "pv9z2x4c6v8b1n3m5k7j9h2g",
"warehouseId": "wh3b8n5k2j7h9g4f1d6s0a8q",
"quantity": 12,
"type": "incoming",
"notes": "Diferencia de inventario"
},
{
"productVariantId": "pv1a3s5d7f9g2h4j6k8l0z2x",
"warehouseId": "wh3b8n5k2j7h9g4f1d6s0a8q",
"quantity": 3,
"type": "outgoing",
"notes": null
}
],
"appliedAt": "2026-01-31T18:24:00.000Z",
"createdAt": "2026-01-31T18:24:00.000Z",
"updatedAt": "2026-01-31T18:24:00.000Z"
}El campo status puede ser draft, applied o voided.
Problemas comunes
| Código | HTTP | Causa |
|---|---|---|
validation_error | 400 | Falta referenceId, type inválido o quantity ≤ 0. |
unauthorized | 401 | API key ausente o inválida. |
not_found | 404 | El referenceId o la warehouseId no existen. |
insufficient_stock | 409 | Una salida (out) deja la existencia por debajo de cero. |
Listar ajustes
GET /inventory-adjustmentsAcepta los parámetros de : start, limit, updatedSince, from, to y metadata.
curl "https://api-pos.zelta.dev/public/v1/inventory-adjustments?limit=30&metadata=true" \
-H "Authorization: Bearer zpk_live_xxx"Ejemplo JS
const res = await fetch('https://api-pos.zelta.dev/public/v1/inventory-adjustments?limit=30&metadata=true', {
headers: { 'Authorization': `Bearer ${process.env.ZELTA_POS_API_KEY}` }
});
const data = await res.json();Ejemplo Py
import requests
res = requests.get(
'https://api-pos.zelta.dev/public/v1/inventory-adjustments',
headers={'Authorization': 'Bearer zpk_live_xxx'},
params={'limit': 30, 'metadata': 'true'}
)
data = res.json()Respuesta 200 OK:
{
"data": [
{
"id": "kx7p2m9q3v8r1n6t4w0y5z2a",
"number": "ADJ-000142",
"warehouseId": "wh3b8n5k2j7h9g4f1d6s0a8q",
"status": "applied",
"reason": "Ajuste por conteo físico de enero",
"notes": null,
"appliedAt": "2026-01-31T18:24:00.000Z",
"createdAt": "2026-01-31T18:24:00.000Z",
"updatedAt": "2026-01-31T18:24:00.000Z"
}
],
"metadata": { "total": 142 }
}Obtener un ajuste
GET /inventory-adjustments/{id}| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string (cuid2) | Sí | Identificador del ajuste. |
Devuelve el objeto del ajuste directamente (sin envoltorio), con la misma estructura que la respuesta de creación. Si no existe, responde 404 not_found.
Transferencias entre bodegas
Una transferencia mueve stock de una bodega a otra. En Zelta POS la transferencia se envía y se recibe de inmediato, por lo que el stock se descuenta del origen y se acredita en el destino en la misma operación.
Crear una transferencia
POST /warehouse-transfers| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
fromWarehouseId | string (cuid2) | Sí | Bodega de origen. |
toWarehouseId | string (cuid2) | Sí | Bodega de destino. |
notes | string (≤500) | No | Nota general de la transferencia. |
items | array | Sí | Mínimo un ítem. |
items[].referenceId | string | Sí | Identificador externo de la variante. |
items[].quantity | number (>0) | Sí | Cantidad a transferir. |
items[].notes | string | No | Nota por línea. |
curl -X POST "https://api-pos.zelta.dev/public/v1/warehouse-transfers" \
-H "Authorization: Bearer zpk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"fromWarehouseId": "wh3b8n5k2j7h9g4f1d6s0a8q",
"toWarehouseId": "wh5d2f8g1h4j7k0l3z6x9c2v",
"notes": "Reabastecimiento sucursal centro",
"items": [
{ "referenceId": "SKU-1001", "quantity": 6 }
]
}'Ejemplo JS
const res = await fetch('https://api-pos.zelta.dev/public/v1/warehouse-transfers', {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.ZELTA_POS_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
fromWarehouseId: 'wh3b8n5k2j7h9g4f1d6s0a8q',
toWarehouseId: 'wh5d2f8g1h4j7k0l3z6x9c2v',
notes: 'Reabastecimiento sucursal centro',
items: [
{ referenceId: 'SKU-1001', quantity: 6 }
]
})
});
const data = await res.json();Ejemplo Py
import requests
res = requests.post(
'https://api-pos.zelta.dev/public/v1/warehouse-transfers',
headers={'Authorization': 'Bearer zpk_live_xxx', 'Content-Type': 'application/json'},
json={
'fromWarehouseId': 'wh3b8n5k2j7h9g4f1d6s0a8q',
'toWarehouseId': 'wh5d2f8g1h4j7k0l3z6x9c2v',
'notes': 'Reabastecimiento sucursal centro',
'items': [
{ 'referenceId': 'SKU-1001', 'quantity': 6 }
]
}
)
data = res.json()Respuesta 201 Created:
{
"id": "tr8h3k6m9p2q5v8r1n4t7w0y",
"number": "TRF-000087",
"fromWarehouseId": "wh3b8n5k2j7h9g4f1d6s0a8q",
"toWarehouseId": "wh5d2f8g1h4j7k0l3z6x9c2v",
"status": "received",
"notes": "Reabastecimiento sucursal centro",
"items": [
{
"productVariantId": "pv9z2x4c6v8b1n3m5k7j9h2g",
"quantity": 6,
"notes": null
}
],
"createdAt": "2026-01-31T19:02:00.000Z",
"updatedAt": "2026-01-31T19:02:00.000Z"
}El campo status puede ser draft, sent, received o cancelled.
Problemas comunes
| Código | HTTP | Causa |
|---|---|---|
validation_error | 400 | Falta fromWarehouseId, toWarehouseId, referenceId o quantity ≤ 0. |
unauthorized | 401 | API key ausente o inválida. |
not_found | 404 | Una bodega o referenceId no existe. |
insufficient_stock | 409 | La bodega de origen no tiene existencias suficientes. |
Listar transferencias
GET /warehouse-transfersAcepta los parámetros de . Devuelve { "data": [...] } y, con ?metadata=true, agrega { "metadata": { "total": N } }.
Obtener una transferencia
GET /warehouse-transfers/{id}| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string (cuid2) | Sí | Identificador de la transferencia. |
Devuelve el objeto de la transferencia directamente. Si no existe, responde 404 not_found.
Kardex (stock ledger)
El kardex es un registro de solo lectura de todos los movimientos de existencias. Cada entrada refleja el saldo antes y después del movimiento y su origen (compra, venta, ajuste o transferencia).
Consultar el kardex
GET /stock-ledgerAcepta los parámetros de : start, limit, updatedSince, from, to y metadata.
curl "https://api-pos.zelta.dev/public/v1/stock-ledger?from=2026-01-01&to=2026-01-31" \
-H "Authorization: Bearer zpk_live_xxx"Ejemplo JS
const res = await fetch('https://api-pos.zelta.dev/public/v1/stock-ledger?from=2026-01-01&to=2026-01-31', {
headers: { 'Authorization': `Bearer ${process.env.ZELTA_POS_API_KEY}` }
});
const data = await res.json();Ejemplo Py
import requests
res = requests.get(
'https://api-pos.zelta.dev/public/v1/stock-ledger',
headers={'Authorization': 'Bearer zpk_live_xxx'},
params={'from': '2026-01-01', 'to': '2026-01-31'}
)
data = res.json()Respuesta 200 OK:
{
"data": [
{
"id": "le2k5m8p1q4v7r0n3t6w9y2z",
"warehouseId": "wh3b8n5k2j7h9g4f1d6s0a8q",
"productVariantStockId": "ps4f7g0h3j6k9l2z5x8c1v4b",
"type": "incoming",
"origin": "adjustment",
"originId": "kx7p2m9q3v8r1n6t4w0y5z2a",
"previousQty": 40,
"qty": 12,
"newQty": 52,
"reason": "Diferencia de inventario",
"createdAt": "2026-01-31T18:24:00.000Z"
}
]
}Para cada entrada, type es incoming u outgoing, y origin puede ser purchase, sale, adjustment, transfer o null. Los campos productVariantStockId, origin, originId y reason pueden ser null.
Siguientes pasos
- — registra entradas de stock desde facturas de proveedor.
- — consulta existencias por variante.
- — descubre las bodegas y sucursales disponibles.
- — paginación, sincronización y códigos de error.