Changelog
Cambios de la API pública de Posdata, versión por versión.
Aquí anunciamos cada cambio de la API y de los webhooks. Los cambios que rompan la compatibilidad (quitar o renombrar un campo, un código de error, un permiso o un tipo de evento) no ocurren sin una nueva versión y un aviso previo. Agregar campos, endpoints, filtros o tipos de evento no se considera un cambio que rompe: tu integración debe tolerar campos nuevos.
v1.0.0 — actualización — 2026-10-20 (compras a proveedores)
Las compras a proveedores. La API no tiene endpoints de proveedores ni de compras: el negocio las registra desde la app y las ves como movimientos de stock. Detalle en Cómo funciona el stock.
origin_type: "purchase"en el movimiento de stock (GET /inventory/movementsy el webhookinventory.movement.created): la entrada de una compra recibida. Sube el costo promedio con el costo de la compra (precio menos descuento, más flete y el impuesto que el negocio no descuenta).origin_type: "purchase_return": una salida de mercancía devuelta al proveedor. Sale al costo promedio.origin_type: "reversal"también cubre ahora la anulación de una compra (una salida que deshace la entrada), además de la reposición de una venta anulada (una entrada).- Son valores nuevos de un campo que ya existe: si tu integración ramifica por
origin_type, trátalos como casos más. No cambia ningún campo ni endpoint.
v1.0.0 — actualización — 2026-10-20 (traslados entre bodegas)
Los traslados entre bodegas con mercancía en tránsito. La API no tiene endpoints de traslados: los ves en los movimientos, el kardex y el valor del inventario. Detalle en Cómo funciona el stock.
origin_type: "transfer"en el movimiento de stock (GET /inventory/movementsy el webhookinventory.movement.created): una salida en la bodega de origen al despachar y una entrada en la de destino al recibir (o en la de origen, si se devuelve). Un traslado no cambia el costo promedio. Es un valor nuevo de un campo que ya existe: si tu integración ramifica pororigin_type, trátalo como un caso más.transferen las filas del kardex (campo nuevo,nullsi la fila no es de un traslado):{ id, number, kind, counterpart }, con el número del traslado y la bodega del otro extremo.in_transit_valueahora es real enGET /inventory/valuation(antes siempre0): el valor de la mercancía despachada y aún no recibida, aparte detotal_value(no está en ningún nivel). Conwarehouse_idcuenta lo que viene hacia esa bodega.in_transitenGET /inventory/valuation(campo nuevo): el detalle por línea. Una línea sin costo conocido viene conunit_costyvalueennully se cuenta enmissing_cost_lines; nunca se valora en0.- Todos los cambios son aditivos: tu integración debe tolerar campos y valores nuevos.
v1.0.0 — actualización — 2026-10-20
Costos, kardex y valor del inventario. Todo el detalle en Kardex y costo promedio y Valor del inventario.
unit_costenPOST /inventory/movements: una entrada (type: "in") puede declarar lo que costó cada unidad base. Alimenta el costo promedio ponderado móvil de la cuenta (uno por producto). Es opcional y debe ser mayor que0: si no lo conoces, no lo envíes. Contype: "out"responde400 VALIDATION_ERROR; una salida sale siempre al costo promedio.GET /inventory/kardex(permisoinventory:read): el libro de un producto, con cada movimiento, conteo y ajuste de costo en orden y el saldo corrido. Filtroswarehouse_id,variant_id,from,to,typeyorder. Pagina conpageypage_size(máximo 200), no con cursor. Con la cuenta enlegacyresponde409 STOCK_MODE_LEGACY.GET /inventory/valuation(permisoinventory:costs): el valor del inventario hoy o a una fecha de corte (at), por bodega. Los niveles negativos y los productos sin costo no suman: vienen aparte ennegativesymissing_cost, nunca valorados en0. Incluyecomputed_at.- Nuevo permiso
inventory:costs: ver costos y valores del inventario. Se pide aparte deinventory:read: con soloinventory:readel kardex trae cantidades y saldos y todo costo y valor viene ennull(costs_hidden: true). Las llaves existentes no lo tienen; créalo en una llave nueva (cuenta.posdata.so → Desarrolladores) solo si lo necesitas. reason_codeen el movimiento de stock (campo nuevo,nullsi no aplica): el motivo catalogado de un ajuste hecho en la app (shrinkage,damage,expired,theft,internal_use,supplier_return,found,correction,otherotransfer_shortage). También llega endatadel webhookinventory.movement.created.- Todos los cambios son aditivos: tu integración debe tolerar campos nuevos en el movimiento y en el webhook.
v1.0.0 — actualización — 2026-10-14
Packs y combos como producto.
kind: "kit"en los productos: un pack o combo agrupa otros productos bajo un precio propio (un six-pack, un kit escolar, un combo de restaurante) y, al venderse, descuenta el stock de cada producto que contiene. El campokinddel producto ahora puede sersimple,compositeokit. Es un cambio aditivo en la respuesta: si tu integración ramifica porkind, trata el valor nuevo como un caso más, no como un error.stockesnullen un pack, igual que en un producto que se arma con receta: el stock lo tienen los productos que contiene.- Mover o contar el stock de un pack (
POST /inventory/movementsyPOST /inventory/counts) responde422 COMPOSITE_STOCK_UNSUPPORTED, como con las recetas: mueve o cuenta el stock de los productos que contiene.
v1.0.0 — actualización — 2026-09-29
El stock oficial por bodega. Todo el detalle en Cómo funciona el stock.
stockpublicado en las cuentas que ya llevan el stock en la nube (todas sus cajas principales con la versión de Posdata que lo soporta; el paso es automático): elstockde un producto es la suma de sus niveles y cada variante trae su propiostock(campo nuevo). Mientras la cuenta no haya pasado,stocksigue siendonull. Ahora es unnumber(antesinteger): puede tener decimales en productos por peso y ser negativo.GET /inventory/levels: el stock por (bodega, producto, variante), conavailable(el stock menos el margen de la API) y el último conteo. Filtrosproduct_id,variant_idywarehouse_id.POST /inventory/counts: registra un conteo físico en el instante en que se hizo (counted_at); las ventas posteriores se suman encima.counted_quantityes entero, salvo en productos que se venden por peso. Permisoinventory:writeeIdempotency-Key.POST /inventory/movements: con el stock en la nube, una salidaoutes atómica y nunca compromete las últimas unidades que el negocio reserva para sus cajas (el margen de la API, 2 por defecto, se ajusta en cuenta.posdata.so → Inventario → Configuración). Si no alcanza, responde el nuevo código409 INSUFFICIENT_STOCKconavailabley no registra nada; antes, la API no verificaba existencias. Ahora acepta variantes (variant_id) yquantitycon decimales en productos que se venden por peso.- Nuevo código
STOCK_MODE_LEGACY(409): lo responden los niveles, los conteos y los movimientos de variantes mientras la cuenta no lleve el stock en la nube. VARIANT_STOCK_UNSUPPORTEDqueda obsoleto y ya no se emite: los movimientos de variantes se aceptan cuando la cuenta lleva el stock en la nube; antes de eso responden409 STOCK_MODE_LEGACY. El código se conserva en el catálogo hasta una nueva versión de la API. Si tu integración ramificaba por él, trataSTOCK_MODE_LEGACYde la misma forma.- Permisos:
inventory:readahora incluye el stock por bodega einventory:write, los conteos. - Webhooks nuevos:
inventory.count.created(un conteo físico, desde una caja o por la API) einventory.stock.negative(un nivel contado quedó negativo porque una caja vendió sin internet lo que ya no había).
v1.0.0 — actualización — 2026-09-28
- Editar productos y variantes:
PATCH /products/{id}(nombre, descripciones, SKU, categoría, precios, clase fiscal, estado) yPATCH /products/{id}/variants/{variantId}(etiqueta, SKU, precios, estado). El cambio llega a las cajas sin stock: cada caja conserva el suyo. Solo funciona cuando todos los dispositivos del negocio tienen la versión de Posdata que lo soporta; si no, responde el nuevo código409 DEVICES_OUTDATEDcon la lista de dispositivos y no modifica nada. El permisoproducts:writeahora incluye estas ediciones, y emitenproduct.updated. Detalle en Productos: se crean y se editan. occurred_aten las ventas: cuándo se registró la venta en la caja (en ventas sincronizadas antes del 28-sep-2026, igual a la hora de llegada). Nuevos filtrosoccurred_sinceyoccurred_untilenGET /sales, y el reporteGET /reports/daily-salesahora agrupa poroccurred_at.created_atsigue siendo la hora de llegada a la nube. Mira Las ventas traen dos fechas.- Búsqueda literal: en
q, los caracteres%y_se buscan tal cual, no como comodines. stocken productos: el campo entró al contrato, todavía ennull. Se publicó con la actualización del 2026-09-29 (arriba).
v1.0.0 — 2026-09-28
Primera versión pública.
- API REST en
https://api.posdata.so/public/v1(pruebas:https://apidev.posdata.so/public/v1), incluida en el plan Pro. - Autenticación con API keys de cuenta (
pdk_live_/pdk_test_) y 12 permisos de mínimo privilegio. - Lectura de cuenta y frescura de datos (
/me), productos y variantes, categorías, clientes, bodegas, movimientos de inventario, ventas, documentos electrónicos, cotizaciones, turnos de caja, ventas por día y registro de eventos. - Escritura: crear y editar categorías y clientes, crear productos sin variantes (con stock inicial
opcional) y registrar movimientos de inventario de productos sin variantes. Todo
POSTexigeIdempotency-Key. La edición de productos y variantes llegó con la actualización del mismo día (arriba). - Webhooks firmados con HMAC-SHA256 (
api_version2026-09-28) para 12 tipos de evento, con reintentos durante unas 28 horas y reconciliación conGET /events. - Límites: 300 peticiones por minuto por key, 600 por cuenta y 60 escrituras por minuto por key.
Limitaciones conocidas de esta versión: Lo que la API no hace en la versión 1.