Saltar a contenido

Reservar stock al tomar un pedido

Cómo apartar productos mientras un cliente compra, para que nadie más los venda antes de que el pedido se pague y se emita la boleta o factura. Pensado para tiendas online, tótems de autoatención y cualquier canal que tome pedidos fuera de la caja.

Esta página está escrita para que la entienda cualquier persona. La primera mitad explica la idea sin tecnicismos; la segunda trae los llamados a la API paso a paso.

El problema que resuelve

Una tienda tiene una zapatilla talla 42. A las 10:00 Ana la pone en su carro en la página web y empieza a escribir los datos de su tarjeta. A las 10:01 Pedro entra a la tienda física y se la lleva. Ana paga a las 10:03 un producto que ya no existe: hay que llamarla, pedirle disculpas y devolverle la plata.

La reserva evita eso. Funciona igual que cuando en una tienda le pides al vendedor "guárdamela, voy al cajero y vuelvo": el producto sigue en la bodega, pero queda apartado a tu nombre por un rato. Si vuelves, es tuyo. Si no vuelves, se libera y lo puede comprar otro.

Las tres ideas que hay que entender

1. Reservar no es descontar. Al reservar, el stock de la bodega no cambia. Lo que baja es lo disponible para vender. El stock recién se descuenta al emitir la boleta, factura o guía.

2. Toda reserva tiene vencimiento. Si el cliente abandona la compra, nadie tiene que acordarse de devolver nada: la reserva vence sola y el producto vuelve a estar disponible.

3. El pedido confirmado protege el stock por más tiempo. Mientras el cliente está comprando, la reserva dura minutos. Cuando el pedido queda confirmado (se crea la nota de venta), pasa a durar horas o días, para dar tiempo a preparar y despachar.

Un ejemplo con números

La tienda tiene 10 zapatillas en bodega. Ana compra 2.

Momento Qué pasa En bodega Reservado Disponible para vender
Antes Nada 10 0 10
Ana agrega 2 al carro y va a pagar Se crea la reserva 10 2 8
Ana paga y el pedido queda confirmado La reserva pasa al pedido y dura más 10 2 8
Se emite la boleta Baja el stock y la reserva se da por cumplida 8 0 8

Si Ana hubiera abandonado la compra, la segunda fila se deshace sola al vencer la reserva: 10 en bodega, 0 reservado, 10 disponibles.

En ningún momento hubo dos personas comprando las mismas unidades, y el número "disponible para vender" nunca mintió.

Para qué canales sirve

El mecanismo es el mismo para todos; solo cambia quién toma el pedido.

Canal Cómo se usa la reserva
Tienda online (e-commerce) Se reserva cuando el cliente agrega al carro o entra a pagar. Es el caso más común y el que se usa en los ejemplos de esta página.
Tótem o kiosco de autoatención El cliente arma su pedido en la pantalla y pasa a pagar o retirar en caja. La reserva aparta los productos entre que confirma en el tótem y llega a la caja.
App móvil de pedidos Igual que la tienda online: el carro de la app reserva mientras el cliente termina la compra.
Marketplaces (MercadoLibre, Falabella y similares) Al llegar una orden del marketplace se reserva de inmediato, para que el mostrador no venda esa unidad antes de procesarla.
Venta por WhatsApp, teléfono o redes El vendedor aparta los productos mientras el cliente transfiere o confirma. Si no paga, se liberan solos.
Retiro en tienda El cliente compra ahora y retira más tarde: el producto queda apartado hasta el retiro.
Vendedores en terreno y pedidos de empresas El pedido se toma hoy y se factura y despacha después; la reserva asegura que lo prometido siga en bodega.
Varias tiendas o canales con una misma bodega Todos leen el mismo "disponible", así que ninguno vende lo que otro ya apartó.

Cada reserva y cada pedido llevan un campo origen (por ejemplo ECOMMERCE, TOTEM, WHATSAPP) para saber después por qué canal entró.

Palabras que vas a ver

Palabra Qué significa
Token del carro El nombre que tu sistema le pone a cada carro o pedido en curso, por ejemplo carro-web-8f3a2b. Lo inventas tú (máximo 64 caracteres) y con él identificas la reserva en todos los llamados.
Stock físico Lo que hay en la bodega.
Reservado Lo que está apartado para carros y pedidos que todavía no se emiten.
Disponible (atpFisico) Stock físico menos reservado. Es lo que ve el cajero.
Disponible para publicar (atpPublicable) El disponible menos el colchón. Es el número que debe mostrar tu tienda.
Colchón Unidades que la empresa decide no ofrecer en línea, como margen de seguridad frente a las ventas de mostrador. Si el colchón es 1 y hay 8 disponibles, la web muestra 7.
Vencimiento Cuánto dura una reserva si nadie la renueva. En la API aparece como ttl, en minutos.
Nota de venta El pedido confirmado en OpenTPV. No es un documento tributario: es el paso previo a la boleta, factura o guía.
Documentar Convertir la nota de venta en boleta, factura o guía. Es el momento en que baja el stock.

El recorrido completo

1. Tu sistema arranca       → pregunta la configuración de la empresa
2. El cliente mira productos → pregunta cuánto hay disponible para publicar
3. El cliente va a pagar     → RESERVA los productos del carro
   … sigue comprando         → renueva la reserva para que no venza
   … se arrepiente           → libera la reserva (o la deja vencer sola)
4. El cliente paga           → crea la NOTA DE VENTA indicando el token del carro
                               (la reserva pasa al pedido y dura más)
5. Se prepara el pedido      → DOCUMENTA la nota de venta: sale la boleta o factura,
                               baja el stock y la reserva queda cumplida
   … o el pedido se cancela  → ANULA la nota de venta: la reserva se libera

Antes de empezar

  1. Tener las credenciales de acceso a la API. Ver Primeros pasos.
  2. Pedirle a la empresa que revise ERP → Opciones → E-Commerce, donde se define cuánto duran las reservas, desde qué bodega se vende y el colchón. La tabla completa está al final, en "Configuración".
  3. Decidir con la empresa si el stock debe bajar cuando la API emite el documento (opción "API descuenta stock al emitir"). Viene apagada. Con ella apagada la reserva igual funciona, pero al emitir la boleta el stock de la bodega no se mueve y hay que ajustarlo por otra vía.

Todos los llamados usan la misma URL base y la misma sesión:

https://api.opentpv.cl
Authorization: Bearer <token de sesión>

Paso 1: leer la configuración

Una vez, al iniciar tu sistema:

curl https://api.opentpv.cl/reservas/configuracion \
  -H "Authorization: Bearer eyJhbGciOi..."
{
  "momentoReserva": "CHECKOUT",
  "ttlWebMinutos": 15,
  "ttlNotaVentaMinutos": 1440,
  "ttlMaximoMinutos": 4320,
  "bodegaEcommerce": 0,
  "buffer": 0,
  "bufferEsPorcentaje": false
}
Campo Qué te dice
momentoReserva Cuándo debes reservar: CARRO (al agregar cada producto), CHECKOUT (al entrar a pagar) o NINGUNO (no reservar, solo consultar disponibilidad). La API no te obliga: respetarlo es tarea de tu sistema.
ttlWebMinutos Cuánto dura la reserva de un carro si no la renuevas. En el ejemplo, 15 minutos.
ttlNotaVentaMinutos Cuánto dura la reserva una vez que el pedido está confirmado. En el ejemplo, 1.440 minutos (24 horas).
ttlMaximoMinutos El máximo que puedes pedir al reservar.
bodegaEcommerce 0 si la tienda comparte bodega con el mostrador. Un número del 1 al 20 si hay una bodega solo para ventas en línea; en ese caso la API usa siempre esa bodega e ignora la que envíes.
buffer, bufferEsPorcentaje El colchón, en unidades o en porcentaje.

Paso 2: mostrar cuánto hay disponible

Para pintar el catálogo o validar el carro. Pide varios códigos de una vez, separados por coma:

curl "https://api.opentpv.cl/reservas/disponibilidad?codigos=A001,B002&bodega=1" \
  -H "Authorization: Bearer eyJhbGciOi..."
[
  { "codigo": "A001", "bodega": 1, "stockFisico": 10, "reservado": 2,
    "buffer": 1, "atpFisico": 8, "atpPublicable": 7 }
]

Cómo leerlo: hay 10 en bodega, 2 apartadas para otros clientes y 1 de colchón. Tu tienda puede ofrecer 7.

Muestra siempre atpPublicable

Si publicas stockFisico o atpFisico vas a ofrecer unidades que ya están apartadas o que la empresa decidió no vender en línea.

Un código que no existe simplemente no aparece en la respuesta.

Paso 3: reservar

Cuando corresponda según momentoReserva, envía el carro completo:

curl -X POST https://api.opentpv.cl/reservas \
  -H "Authorization: Bearer eyJhbGciOi..." \
  -H "Content-Type: application/json" \
  -d '{
    "token": "carro-web-8f3a2b",
    "bodega": 1,
    "origen": "ECOMMERCE",
    "usuario": "ana@correo.cl",
    "lineas": [
      { "codigo": "A001", "cantidad": 2 },
      { "codigo": "B002", "cantidad": 1 }
    ]
  }'
Campo Obligatorio Contenido
token Sí El identificador del carro que inventa tu sistema.
lineas Sí Productos y cantidades del carro.
bodega No Bodega de la que se aparta. Por defecto 1.
ttlMinutos No Duración que pides. Si se omite se usa ttlWebMinutos.
origen No Canal del pedido. Por defecto ECOMMERCE.
usuario No Quién compra, para dejar rastro.

Si hay stock, la respuesta dice hasta cuándo está apartado:

{
  "exito": true,
  "token": "carro-web-8f3a2b",
  "bodega": 1,
  "expiraEn": "2026-08-10T10:15:00",
  "segundosRestantes": 900,
  "lineas": [
    { "codigo": "A001", "cantidad": 2 },
    { "codigo": "B002", "cantidad": 1 }
  ],
  "faltantes": []
}

Si falta stock de cualquier producto, no se reserva nada y la respuesta (código 409) dice qué faltó y cuánto queda:

{
  "exito": false,
  "faltantes": [
    { "codigo": "A001", "solicitado": 2, "disponible": 1, "stockFisico": 3 }
  ]
}

Muéstrale al cliente lo que falta ("solo queda 1") y vuelve a reservar con las cantidades corregidas.

Tres reglas de este paso:

  • Es todo o nada. O se reserva el carro entero o no se reserva nada. Así el cliente nunca paga un pedido incompleto sin saberlo.
  • Reenviar el mismo token reemplaza, no suma. Cada vez que el carro cambie, vuelve a enviar el carro completo con el mismo token. No necesitas calcular diferencias.
  • Si dos clientes piden la última unidad al mismo tiempo, gana uno solo. El otro recibe el 409.

Mientras el cliente sigue comprando

Renovar para que la reserva no venza mientras el cliente sigue activo (por ejemplo, cada 5 minutos con el carro abierto):

curl -X PATCH "https://api.opentpv.cl/reservas/carro-web-8f3a2b/renovar" \
  -H "Authorization: Bearer eyJhbGciOi..."

Si responde 404, la reserva ya venció: otro cliente pudo tomar esas unidades, así que hay que volver al Paso 3.

Liberar cuando el cliente vacía el carro o abandona la compra. No es obligatorio, porque la reserva vence sola, pero devuelve el stock de inmediato:

# Todo el carro
curl -X DELETE https://api.opentpv.cl/reservas/carro-web-8f3a2b \
  -H "Authorization: Bearer eyJhbGciOi..."

# Un solo producto
curl -X DELETE "https://api.opentpv.cl/reservas/carro-web-8f3a2b/lineas/B002?bodega=1" \
  -H "Authorization: Bearer eyJhbGciOi..."

Consultar qué pasó con un carro (útil si el cliente vuelve más tarde):

curl https://api.opentpv.cl/reservas/carro-web-8f3a2b \
  -H "Authorization: Bearer eyJhbGciOi..."

Devuelve cada línea con su estado: ACTIVA (apartada), CONSUMIDA (ya se emitió el documento), LIBERADA (se soltó a mano o se anuló el pedido), VENCIDA (se cumplió el tiempo) o INCUMPLIDA (ver "Qué pasa si...").

Paso 4: confirmar el pedido (nota de venta con reserva)

Cuando el cliente paga, crea la nota de venta e indica el token del carro en tokenReserva. Ese campo es lo que une el pedido con lo que estaba apartado:

curl -X POST https://api.opentpv.cl/documento/notaventa \
  -H "Authorization: Bearer eyJhbGciOi..." \
  -H "Content-Type: application/json" \
  -d '{
    "tokenReserva": "carro-web-8f3a2b",
    "origen": "ECOMMERCE",
    "fechaEmision": "2026-08-10",
    "rut": "12345678", "digito": "5",
    "razonSocial": "Ana Pérez",
    "direccion": "Los Aromos 456", "comuna": "Ñuñoa", "ciudad": "Santiago",
    "email": "ana@correo.cl",
    "observaciones": "Pedido web #8912",
    "neto": 25210, "iva": 4790, "total": 30000,
    "items": [
      {
        "codigo": "A001",
        "descripcion": "Zapatilla urbana 42",
        "cantidad": 2,
        "precioUnitario": 15000,
        "totalLinea": 30000,
        "bodega": 1
      }
    ],
    "pagos": [ { "idFormaPago": 2, "formaPago": "WEBPAY", "monto": 30000 } ]
  }'
{
  "success": true,
  "message": "NOTA DE VENTA folio 8912 creada exitosamente",
  "data": {
    "folio": 8912,
    "idDocumento": 2150,
    "total": 30000,
    "estado": "PAGADO"
  }
}

Qué ocurre en este paso:

  • La reserva deja de pertenecer al carro y pasa a pertenecer al pedido. Desde ahora dura lo que indica ttlNotaVentaMinutos (24 horas si no se cambió).
  • El stock todavía no baja. Sigue apartado.
  • Guarda data.folio: es la llave para documentar o anular el pedido.

Revisa advertencia antes de dar el pedido por seguro

Si el carro ya había vencido cuando llegó el pago, la nota de venta se crea igual, pero la respuesta trae data.advertencia avisando que el stock no está garantizado. En ese caso vuelve a consultar la disponibilidad (Paso 2) antes de cobrar o despachar.

Después de este paso deja de renovar el token. Renovar le volvería a poner la duración corta de un carro y le quitaría protección al pedido confirmado.

Los precios de cada línea pasan tal cual al documento del Paso 5. En el ejemplo van con IVA incluido porque el pedido termina en boleta. Si va a terminar en factura o guía, envíalos netos, o mantenlos con IVA incluido y agrega "mntBruto": true al documentar. El detalle está en Pedidos con nota de venta.

Paso 5: emitir el documento

Cuando el pedido está listo, se convierte en boleta, factura o guía:

curl -X POST https://api.opentpv.cl/documento/notaventa/8912/documentar \
  -H "Authorization: Bearer eyJhbGciOi..." \
  -H "Content-Type: application/json" \
  -d '{ "tipoDte": 39, "codigoTerminal": "TERM-01" }'

Aquí pasan las dos cosas que cierran el ciclo:

  • Baja el stock de la bodega (si la empresa activó "API descuenta stock al emitir").
  • La reserva queda cumplida. El disponible no cambia, porque las unidades ya estaban apartadas: salen de "reservado" y salen de la bodega al mismo tiempo.

tipoDte puede ser 39 (boleta), 41 (boleta exenta), 33 (factura), 34 (factura exenta) o 52 (guía de despacho). La respuesta trae folio, token y enlaces al PDF igual que en Emitir documentos. Un pedido no se puede documentar dos veces: el segundo intento recibe 409.

Este paso también lo puede hacer un cajero desde el ERP; el resultado es el mismo. El detalle de este endpoint (receptor distinto, datos de traslado de la guía) está en Pedidos con nota de venta.

Si el pedido se cancela

curl -X POST https://api.opentpv.cl/documento/notaventa/8912/anular \
  -H "Authorization: Bearer eyJhbGciOi..."

La reserva se libera en el momento y las unidades vuelven a estar disponibles. Solo se puede anular mientras el pedido no esté documentado; si ya se emitió la boleta o factura, la reversa es con nota de crédito.

Qué pasa si...

Situación Qué ocurre Qué debe hacer tu sistema
El cliente cierra el navegador sin comprar La reserva vence sola al cumplirse el tiempo. Nada. Si quieres devolver el stock antes, libera el carro.
El cliente se demora mucho en pagar Si no renovaste, la reserva venció. Renovar mientras el cliente esté activo. Si renovar responde 404, reservar de nuevo.
No queda stock suficiente POST /reservas responde 409 con los faltantes. Mostrar cuánto queda y reservar con cantidades menores.
El pago llega cuando la reserva ya venció La nota de venta se crea con advertencia. Revisar disponibilidad antes de cobrar o despachar.
El cliente cambia cantidades o productos La reserva debe reflejar el carro nuevo. Reenviar el carro completo con el mismo token.
Tu sistema envía dos veces el mismo carro El segundo envío reemplaza al primero. No se duplica. Nada.
El cajero vende en mostrador lo que estaba reservado Ver el apartado siguiente. Consultar las reservas incumplidas y avisar al cliente.

Cuando el mostrador vende algo que estaba reservado

En la tienda física, la venta presencial siempre gana: al cliente que tiene el producto en la mano no se le niega la venta. Si el cajero vende unidades que estaban apartadas para un pedido en línea, esa reserva queda marcada como INCUMPLIDA.

Tu sistema debe preguntar cada cierto tiempo si hay reservas incumplidas, avisar al cliente afectado antes de cobrarle (o devolverle la plata si ya pagó) y confirmar que ya las vio:

# ¿Hay reservas incumplidas que no he revisado?
curl "https://api.opentpv.cl/reservas/incumplidas?soloNoAcusadas=true" \
  -H "Authorization: Bearer eyJhbGciOi..."

# Ya las procesé: no me las muestres de nuevo
curl -X POST https://api.opentpv.cl/reservas/incumplidas/acusar \
  -H "Authorization: Bearer eyJhbGciOi..." \
  -H "Content-Type: application/json" \
  -d '{ "ids": [101, 102] }'

Dos formas de que esto casi nunca ocurra: usar una bodega solo para ventas en línea, o definir un colchón.

Tótems de autoatención

En un tótem el recorrido es el mismo, con tiempos más cortos:

  1. El cliente arma su pedido en la pantalla. El tótem consulta la disponibilidad (Paso 2) para no ofrecer lo que no hay.
  2. Al confirmar, el tótem reserva (Paso 3) con un token propio, por ejemplo totem-02-000451, y origen TOTEM.
  3. El tótem crea la nota de venta con tokenReserva (Paso 4) y le entrega al cliente un comprobante con el número de pedido.
  4. En la caja, el cajero busca la nota de venta y emite la boleta (Paso 5). Ahí baja el stock.
  5. Si el cliente nunca llega a la caja, la reserva vence y los productos vuelven a estar disponibles.

Como el cliente paga a los pocos minutos, conviene pedir una duración corta al reservar (ttlMinutos) y acordar con la empresa un valor bajo para la reserva del pedido confirmado.

El kiosco de OpenTPV (catálogo y autoservicio) ya trabaja así por dentro: no necesita integración. Esta sección es para quien construye su propio tótem sobre la API.

Empresas con varias razones sociales

Caso típico: la razón social de la tienda online le vende al cliente final y emite su boleta en su propio sistema; el stock está en otra razón social que usa OpenTPV. Entre empresas, la que tiene el stock le vende a la tienda, y la mercadería viaja directo al cliente final.

Por cada OpenTPV que aporta stock:

1. Reserva contra la bodega de OpenTPV              (igual que arriba)
2. Nota de venta a nombre del CLIENTE FINAL         (el pedido, con su trazabilidad)
3. Documentar con tipoDte 52 (guía de despacho) y
   codigoClienteReceptor = código de la tienda online como cliente en OpenTPV:
   → la guía sale a nombre de la tienda online
   → el domicilio del cliente final queda como destino del traslado
   → baja el stock y la reserva queda cumplida
4. A fin de mes, en el ERP: facturación masiva de guías → una factura a la
   tienda online que reúne todas las guías del período

Reglas de este caso:

  • Una guía por pedido. La guía ampara un traslado concreto; cada paquete que viaja necesita la suya. Lo que se junta es la factura mensual.
  • La tienda online debe existir como cliente en OpenTPV.
  • codigoClienteReceptor solo aplica a factura (33, 34) y guía (52); las boletas no admiten un receptor distinto al del pedido.
  • Ajustar la duración de la reserva del pedido confirmado al tiempo real de despacho (por ejemplo 2.880 minutos, dos días). Si vence antes de emitir la guía, el mostrador podría vender ese stock.
  • El motivo de traslado entre razones sociales conviene validarlo con el contador de la empresa.

Configuración

En ERP → Opciones → E-Commerce:

Opción Valor inicial Qué hace
API descuenta stock al emitir Apagado Si está apagado, emitir por API no mueve el stock de la bodega. Activarlo cambia el comportamiento de todas las integraciones de la empresa, por eso el ERP pide confirmación.
Reservar en CHECKOUT Cuándo debe reservar la tienda: CARRO, CHECKOUT o NINGUNO.
Duración reserva (min) 15 Cuánto dura la reserva de un carro.
Reserva pedido confirmado (min) 1440 Cuánto dura la reserva una vez creada la nota de venta.
Bodega web 0 0 = comparte bodega con el mostrador; 1 a 20 = bodega solo para ventas en línea.
Stock a no publicar (colchón) 0 Unidades o porcentaje que no se ofrecen en línea. Solo aplica con bodega compartida.

El máximo que un integrador puede pedir al reservar es de 4.320 minutos (3 días) y solo lo cambia el equipo de OpenTPV.

La API revisa las reservas vencidas en cada operación, así que el vencimiento funciona sin configurar nada más. Con ventas en línea activas conviene que el equipo de OpenTPV habilite además la revisión periódica, que mantiene todo al día aunque la tienda esté sin movimiento.

Errores frecuentes

  • Mostrar stockFisico o atpFisico en la tienda en vez de atpPublicable.
  • Enviar solo el producto que cambió en vez del carro completo (el token reemplaza, no suma).
  • Seguir renovando el token después de crear la nota de venta.
  • Crear la nota de venta sin tokenReserva: el pedido queda sin stock apartado y la reserva del carro vence a los pocos minutos.
  • Cobrar sin revisar advertencia ni las reservas incumplidas.
  • Creer que reservar descuenta stock, o que anular lo repone. La reserva nunca toca el stock de la bodega: solo lo aparta.

Resumen de llamados

Para Llamado
Leer la configuración GET /reservas/configuracion
Ver disponibilidad GET /reservas/disponibilidad?codigos=A001,B002&bodega=1
Reservar o actualizar el carro POST /reservas
Renovar la reserva PATCH /reservas/{token}/renovar
Consultar un carro GET /reservas/{token}
Liberar el carro DELETE /reservas/{token}
Liberar un producto DELETE /reservas/{token}/lineas/{codigo}
Reservas incumplidas GET /reservas/incumplidas
Marcar incumplidas como revisadas POST /reservas/incumplidas/acusar
Confirmar el pedido POST /documento/notaventa con tokenReserva
Emitir boleta, factura o guía POST /documento/notaventa/{folio}/documentar
Cancelar el pedido POST /documento/notaventa/{folio}/anular

El detalle de cada campo está en la referencia de la API.