{"openapi":"3.1.0","info":{"title":"Posdata API","version":"1.0.0","description":"API REST servidor a servidor para cuentas con plan Pro. Autenticación con API key (Bearer). Montos en pesos colombianos enteros; fechas ISO 8601 en UTC.","contact":{"name":"Posdata","url":"https://developers.posdata.so","email":"soporte@posdata.so"}},"servers":[{"url":"https://api.posdata.so/public/v1","description":"Producción (keys pdk_live_)"},{"url":"https://apidev.posdata.so/public/v1","description":"Pruebas (keys pdk_test_, datos de prueba, puede reiniciarse)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key creada en cuenta.posdata.so → Desarrolladores."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string","enum":["UNAUTHENTICATED","INVALID_API_KEY","API_KEY_REVOKED","API_KEY_EXPIRED","API_KEY_WRONG_ENVIRONMENT","ACCOUNT_INACTIVE","PLAN_REQUIRED","INSUFFICIENT_SCOPE","BROWSER_REQUESTS_NOT_ALLOWED","VALIDATION_ERROR","INVALID_JSON","PAYLOAD_TOO_LARGE","INVALID_CURSOR","NOT_FOUND","ROUTE_NOT_FOUND","IDEMPOTENCY_KEY_REQUIRED","IDEMPOTENCY_KEY_REUSED","IDEMPOTENCY_IN_PROGRESS","CONFLICT","SKU_ALREADY_EXISTS","VARIANT_STOCK_UNSUPPORTED","COMPOSITE_STOCK_UNSUPPORTED","NO_WAREHOUSE","DEVICES_OUTDATED","INSUFFICIENT_STOCK","STOCK_MODE_LEGACY","PRODUCT_IN_USE","CATEGORY_IN_USE","CUSTOMER_HAS_SALES","RATE_LIMITED","INTERNAL_ERROR"],"description":"Código estable para ramificar tu integración. Obsoletos (se conservan en el catálogo hasta una nueva versión de la API): `VARIANT_STOCK_UNSUPPORTED` — obsoleto, ya no se emite: las variantes mueven su propio stock."},"message":{"type":"string","description":"Explicación en español, con el siguiente paso."},"param":{"type":"string","description":"Campo que causó el error, si aplica."},"request_id":{"type":"string"}},"additionalProperties":true}}},"Scope":{"type":"string","enum":["products:read","products:write","customers:read","customers:write","inventory:read","inventory:write","sales:read","invoices:read","quotes:read","cash:read","reports:read","events:read","products:delete","customers:delete","inventory:costs"],"description":"- `products:read`: Leer productos, variantes y categorías\n- `products:write`: Crear y editar productos, editar variantes, crear y editar categorías\n- `customers:read`: Leer clientes\n- `customers:write`: Crear y editar clientes\n- `inventory:read`: Leer bodegas, stock por bodega y movimientos de inventario\n- `inventory:write`: Registrar movimientos y conteos de inventario\n- `sales:read`: Leer ventas\n- `invoices:read`: Leer documentos electrónicos (DIAN)\n- `quotes:read`: Leer cotizaciones\n- `cash:read`: Leer turnos y movimientos de caja\n- `reports:read`: Leer reportes agregados\n- `events:read`: Leer el registro de eventos\n- `products:delete`: Eliminar productos, variantes y categorías\n- `customers:delete`: Eliminar clientes\n- `inventory:costs`: Ver costos y valores del inventario (kardex valorizado y valor del inventario)"},"Account":{"type":"object","required":["object","id","business","plan","api_key","data_freshness"],"properties":{"object":{"const":"account"},"id":{"type":"string","format":"uuid","description":"Id de la cuenta (tenant)."},"business":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"currency":{"type":"string"}}},{"type":"null"}]},"plan":{"type":"string","enum":["free","plus","pro","plus_nofe","pro_nofe"]},"api_key":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"environment":{"type":"string","enum":["live","test"]},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/Scope"}},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}}},{"type":"null"}]},"data_freshness":{"type":"object","description":"La API lee lo que las cajas ya subieron. `last_sync_at` es el último cambio que cada caja subió de verdad (null si nunca subió nada): si una caja lleva horas sin subir, sus ventas recientes todavía no aparecen.","properties":{"last_device_sync_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"devices":{"type":"array","items":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"kind":{"type":"string","enum":["primary","satellite","kitchen"]},"platform":{"anyOf":[{"type":"string"},{"type":"null"}]},"last_sync_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}}}}}}}},"ProductVariant":{"type":"object","description":"Variante de un producto. Precios en pesos enteros, digitados como los digita el negocio: con impuestos incluidos cuando su perfil fiscal dice `pricesIncludeTax` (lo normal), antes de impuestos si no.","required":["object","id","product_id","label","sku","base_price","final_price","percent_discount","images","is_default","active","stock","created_at","updated_at"],"properties":{"object":{"const":"product_variant"},"id":{"type":"string","format":"uuid"},"product_id":{"type":"string","format":"uuid"},"label":{"type":"string","description":"Nombre de la variante (\"Talla M / Rojo\")."},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"base_price":{"type":"integer","description":"Precio de lista, antes del descuento propio del producto."},"final_price":{"type":"integer","description":"Precio al que el POS vende esta variante. Si es 0 en la variante, el POS usa el del producto."},"percent_discount":{"type":"number","description":"Descuento del producto sobre `base_price`, en porcentaje (0-100, puede tener decimales)."},"images":{"type":"array","items":{"type":"string","format":"uri"}},"is_default":{"type":"boolean"},"active":{"type":"boolean"},"stock":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stock oficial de la variante (suma de sus bodegas). `null` mientras la cuenta no lleve el stock en la nube."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Product":{"type":"object","description":"Producto del catálogo. Precios en pesos enteros, digitados como los digita el negocio: con impuestos incluidos cuando su perfil fiscal dice `pricesIncludeTax` (lo normal), antes de impuestos si no.","required":["object","id","name","description","description_short","sku","category_id","kind","sellable","active","tax_class","base_price","final_price","percent_discount","base_unit","sold_by_weight","sale_measure","stock","unit_cost","image_url","images","has_variants","variants","deleted_at","created_at","updated_at"],"properties":{"object":{"const":"product"},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"description_short":{"type":"string"},"sku":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"SKU del producto (null si no tiene)."},"category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"kind":{"type":"string","enum":["simple","composite","kit"],"description":"`composite` = se arma desde una receta y no descuenta su propio stock. `kit` = pack o combo: agrupa otros productos con un precio propio y, al venderse, descuenta el stock de cada producto que contiene; tampoco tiene stock propio."},"sellable":{"type":"boolean","description":"`false` = insumo que no se vende por sí solo."},"active":{"type":"boolean"},"tax_class":{"type":"string","enum":["standard","reduced_5","excluded","exempt","service_19","event_package","bag","passthrough"],"description":"Clase fiscal del ítem. `standard` hereda del perfil fiscal del negocio."},"base_price":{"type":"integer","description":"Precio de lista, antes del descuento propio del producto."},"final_price":{"type":"integer","description":"Precio al que el POS vende. Si el producto no tiene descuento es igual a `base_price`."},"percent_discount":{"type":"number","description":"Descuento del producto sobre `base_price`, en porcentaje (0-100, puede tener decimales)."},"base_unit":{"type":"string","description":"Unidad base (und, g, kg, lb, oz, ml, l, doc). Stock y costo se expresan en ella."},"sold_by_weight":{"type":"boolean","description":"Se vende por peso: la cantidad de la línea es un peso en `base_unit`."},"sale_measure":{"type":"string","enum":["unit","weight","area","length","fraction"],"description":"Cómo se vende: por unidad, por peso, por área (m², ancho × alto), por metro lineal o por fracción de una unidad. Solo lectura: se configura desde la app. En área, longitud y fracción la cantidad de la línea tiene decimales en `base_unit` (m², m o unidades)."},"stock":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stock oficial en `base_unit` (suma de todas sus bodegas y variantes; puede tener decimales en productos por peso y ser negativo si una venta ganó la carrera). Es `null` mientras la cuenta no lleve el stock en la nube (sus cajas aún en una versión anterior), en productos sin control de stock y en los que se arman con receta. Por bodega: GET /inventory/levels. Para moverlo: POST /inventory/movements o POST /inventory/counts."},"unit_cost":{"type":"number","description":"Costo promedio ponderado por unidad base (informativo)."},"image_url":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"images":{"type":"array","items":{"type":"string","format":"uri"}},"has_variants":{"type":"boolean"},"variants":{"type":"array","items":{"$ref":"#/components/schemas/ProductVariant"},"description":"Variantes vigentes (no eliminadas)."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Category":{"type":"object","description":"Categoría del catálogo.","required":["object","id","name","description","image_url","sort_order","deleted_at","created_at","updated_at"],"properties":{"object":{"const":"category"},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"image_url":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"sort_order":{"type":"integer"},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Customer":{"type":"object","description":"Cliente del negocio.","required":["object","id","name","last_name","email","phone","person_type","document_type","document_number","contact_channel","deleted_at","created_at","updated_at"],"properties":{"object":{"const":"customer"},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"person_type":{"type":"string","description":"`person` (persona natural) o `company` (persona jurídica)."},"document_type":{"type":"string","description":"Tipo de identificación: CC, TI, NIT, CE, PASAPORTE."},"document_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"contact_channel":{"anyOf":[{"type":"string","description":"Cómo llegó el cliente: none, store, whatsapp, instagram, website, referral."},{"type":"null"}]},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Warehouse":{"type":"object","description":"Bodega del negocio.","required":["object","id","name","address","city","is_default","active","created_at","updated_at"],"properties":{"object":{"const":"warehouse"},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"is_default":{"type":"boolean"},"active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"StockMovement":{"type":"object","description":"Movimiento del libro de inventario (solo se agregan, nunca se editan).","required":["object","id","product_id","variant_id","warehouse_id","type","quantity","reason","reference","unit_cost","reason_code","origin_type","sale_id","created_at","updated_at"],"properties":{"object":{"const":"stock_movement"},"id":{"type":"string","format":"uuid"},"product_id":{"type":"string","format":"uuid"},"variant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"warehouse_id":{"anyOf":[{"type":"string","format":"uuid","description":"null si el movimiento llegó antes que su bodega."},{"type":"null"}]},"type":{"type":"string","description":"Tipo de movimiento tal como lo registró la caja."},"quantity":{"type":"number","description":"Cantidad en la unidad base del producto (puede ser fraccionaria)."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]},"reference":{"anyOf":[{"type":"string","description":"Referencia libre del movimiento."},{"type":"null"}]},"unit_cost":{"anyOf":[{"type":"number","description":"Costo por unidad base al momento del movimiento."},{"type":"null"}]},"reason_code":{"anyOf":[{"type":"string","description":"Motivo catalogado de un ajuste: shrinkage, damage, expired, theft, internal_use, supplier_return, found, correction, other o transfer_shortage. `null` si el movimiento no es un ajuste con motivo."},{"type":"null"}]},"origin_type":{"anyOf":[{"type":"string","description":"sale, purchase, purchase_return (goods given back to a supplier), adjustment, recipe_explosion, reversal (a voided purchase or the restock of an annulled sale), transfer (goods moving between two warehouses of the same business: an `out` at the origin when it is dispatched, an `in` at the destination when it is received or at the origin when it is returned; it never changes the cost)."},{"type":"null"}]},"sale_id":{"anyOf":[{"type":"string","format":"uuid","description":"La venta que causó el movimiento, si aplica."},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"StockLevel":{"type":"object","description":"Stock oficial de un producto (o variante) en una bodega.","required":["object","id","warehouse_id","product_id","variant_id","quantity","available","baseline_quantity","baseline_at","baseline_estimated","baseline_source","negative_alert_open","updated_at"],"properties":{"object":{"const":"stock_level"},"id":{"type":"string","format":"uuid"},"warehouse_id":{"type":"string","format":"uuid"},"product_id":{"type":"string","format":"uuid"},"variant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quantity":{"type":"number","description":"Stock oficial en la unidad base: el último conteo más los movimientos posteriores. Puede ser negativo (una venta ganó la carrera): el negocio debe contar."},"available":{"type":"number","description":"Lo que la API puede comprometer: `quantity` menos el margen de la API (nunca menor que 0)."},"baseline_quantity":{"anyOf":[{"type":"number","description":"Cantidad del último conteo (null si nunca se ha contado)."},{"type":"null"}]},"baseline_at":{"anyOf":[{"type":"string","format":"date-time","description":"Cuándo se hizo el último conteo."},{"type":"null"}]},"baseline_estimated":{"type":"boolean","description":"`true` si el último conteo es una estimación de la migración y conviene contar."},"baseline_source":{"anyOf":[{"type":"string","description":"count, count_sheet, initial, upgrade, migration o api."},{"type":"null"}]},"negative_alert_open":{"type":"boolean","description":"Hay una alerta de stock negativo abierta en este nivel."},"updated_at":{"type":"string","format":"date-time"}}},"StockCount":{"type":"object","description":"Conteo físico de inventario.","required":["object","id","warehouse_id","product_id","variant_id","counted_quantity","counted_at","source","status","estimated","expected_quantity","difference","note","created_at"],"properties":{"object":{"const":"stock_count"},"id":{"type":"string","format":"uuid"},"warehouse_id":{"type":"string","format":"uuid"},"product_id":{"type":"string","format":"uuid"},"variant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"counted_quantity":{"type":"number","description":"Lo que había físicamente."},"counted_at":{"type":"string","format":"date-time","description":"Cuándo se contó."},"source":{"type":"string","description":"count, count_sheet, initial, upgrade, migration o api."},"status":{"type":"string","enum":["applied","historical","pending"],"description":"`applied`: es la base del stock oficial desde su `counted_at`. `historical`: se guardó solo como historial (ya había un conteo más reciente). `pending`: la cuenta todavía no lleva el stock en la nube (una caja lo registró antes del cambio); se tendrá en cuenta cuando la cuenta pase al stock en la nube."},"estimated":{"type":"boolean"},"expected_quantity":{"anyOf":[{"type":"number","description":"Lo que el sistema creía en el instante del conteo."},{"type":"null"}]},"difference":{"anyOf":[{"type":"number","description":"`counted_quantity − expected_quantity`."},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"}}},"InventoryKardex":{"type":"object","description":"El kardex de un producto: cada movimiento, conteo y ajuste de costo en orden, con el saldo y (con el permiso `inventory:costs`) el costo promedio corrido. Sin ese permiso, `unit_cost`, `value_delta`, `avg_cost` y `total_value` vienen en `null` y `costs_hidden` es `true`. Un costo desconocido es `null` (con `missing_cost: true`), nunca 0. Las unidades que entraron sin costo quedan \"sin costo\" (`uncosted_qty`): no entran al promedio ni al valor hasta que se ingrese su costo.","properties":{"object":{"const":"kardex"},"product":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"local_id":{"type":"string"},"name":{"type":"string"}}},"rows":{"type":"array","items":{"type":"object","description":"Una fila del kardex: `key`, `kind` (movement | count | cost_change | cost_adjustment), `at`, `type` (in | out | count | cost), `quantity_in`, `quantity_out`, `level_qty`, `total_qty`, `unit_cost`, `value_delta`, `avg_cost`, `total_value`, `uncosted_qty`, `missing_cost`, `document_number`, `reason_code`, `user_name`…"}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}},"levels":{"type":"array","items":{"type":"object","properties":{"warehouse_id":{"type":"string","format":"uuid"},"variant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quantity":{"type":"number"}}}},"total_qty":{"type":"number","description":"Existencia total del producto al final de lo consultado."},"avg_cost":{"anyOf":[{"type":"number","description":"Costo promedio ponderado al final; `null` si se desconoce o no tienes `inventory:costs`."},{"type":"null"}]},"uncosted_qty":{"anyOf":[{"type":"number","description":"Unidades en existencia sin costo: fuera de `avg_cost` y del valor. `null` si no tienes `inventory:costs`."},{"type":"null"}]},"warehouses":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}}},"costs_hidden":{"type":"boolean","description":"`true` si tu llave no tiene `inventory:costs`."}}},"InventoryValuation":{"type":"object","description":"El valor del inventario hoy o a una fecha (`at`): existencia × costo promedio del producto en ese instante. Los niveles negativos no suman (van en `negatives`: \"cuéntalos\") y los productos (o las unidades de un producto) sin costo van en `missing_cost` sin valor — nunca valorados en 0 ni al costo de otra compra; `uncosted_units` dice cuántas unidades faltan (valor incompleto). Siempre dice cuándo se calculó (`computed_at`): información tardía (una caja sin conexión) puede cambiar un corte ya consultado.","properties":{"object":{"const":"inventory_valuation"},"at":{"type":"string","format":"date-time"},"computed_at":{"type":"string","format":"date-time"},"total_value":{"type":"integer","description":"Pesos enteros."},"by_warehouse":{"type":"array","items":{"type":"object","properties":{"warehouse_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"value":{"type":"integer"}}}},"lines":{"type":"array","items":{"type":"object","properties":{"product_id":{"type":"string","format":"uuid"},"product_name":{"type":"string"},"warehouse_id":{"type":"string","format":"uuid"},"warehouse_name":{"type":"string"},"variant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quantity":{"type":"number"},"uncosted_quantity":{"type":"number","description":"Unidades de `quantity` sin costo, fuera de `value`."},"avg_cost":{"anyOf":[{"type":"number"},{"type":"null"}]},"value":{"anyOf":[{"type":"integer"},{"type":"null"}]}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}},"negatives":{"type":"array","items":{"type":"object"}},"missing_cost":{"type":"array","items":{"type":"object"}},"uncosted_units":{"type":"number","description":"Unidades en existencia sin costo (fuera de `total_value`)."},"in_transit_value":{"type":"integer"},"costs_hidden":{"type":"boolean"}}},"LineTax":{"type":"object","description":"Impuesto cobrado en una línea, congelado al momento de la venta.","required":["code","name","rate","per_unit","base","amount"],"properties":{"code":{"type":"string","description":"Código DIAN del tributo: 01 IVA, 03 ICA, 04 INC, 22 INC bolsas."},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Tarifa en PORCENTAJE entero (19 = 19 %), tal como se cobró. null en impuestos por unidad."},"per_unit":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Valor fijo por unidad (bolsas). null en impuestos por porcentaje."},"base":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"amount":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."}}},"TaxBreakdownEntry":{"type":"object","description":"Total de un tributo en el documento, agrupado por (código, tarifa).","required":["code","rate","per_unit","base","amount"],"properties":{"code":{"type":"string"},"rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Porcentaje entero."},"per_unit":{"anyOf":[{"type":"integer"},{"type":"null"}]},"base":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"amount":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."}}},"DocumentType":{"type":"string","enum":["electronic_invoice","pos_document","pos_adjustment_note","internal_invoice","other"],"description":"`electronic_invoice` = factura electrónica (DIAN 1, CUFE) · `pos_document` = documento equivalente POS electrónico (DIAN 15, CUDE) · `pos_adjustment_note` = nota de ajuste del documento POS (DIAN 26) · `internal_invoice` = factura no electrónica."},"InvoiceSummary":{"type":"object","description":"Resumen de un documento de la venta. El detalle está en GET /invoices/{id}.","required":["id","document_type","status","cufe","prefix","number"],"properties":{"id":{"type":"string","format":"uuid"},"document_type":{"$ref":"#/components/schemas/DocumentType"},"status":{"type":"string"},"cufe":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"CUFE (factura) o CUDE (documento POS)."},"prefix":{"anyOf":[{"type":"string"},{"type":"null"}]},"number":{"type":"integer"}}},"SaleItem":{"type":"object","description":"Línea de una venta.","required":["object","id","product_id","variant_id","item_kind","description","quantity","unit_price","subtotal","discount_amount","unit_cost","tax_class","taxes"],"properties":{"object":{"const":"sale_item"},"id":{"type":"string","format":"uuid"},"product_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"null en líneas libres o si el producto ya no existe."},"variant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"item_kind":{"type":"string","description":"`product` o una línea libre."},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number","description":"Puede ser fraccionaria (ventas por peso)."},"unit_price":{"type":"integer","description":"Precio unitario con los impuestos porcentuales incluidos."},"subtotal":{"type":"integer","description":"Total NETO de la línea con impuestos incluidos: `round(unit_price × quantity) - discount_amount`."},"discount_amount":{"type":"integer","description":"Descuento que el cajero dio en la línea, con impuestos incluidos: el propio de la línea más su parte del descuento de la venta. 0 si no hubo."},"unit_cost":{"anyOf":[{"type":"number","description":"Costo unitario congelado al vender."},{"type":"null"}]},"tax_class":{"type":"string"},"taxes":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/LineTax"}},{"type":"null"}],"description":"null en líneas antiguas sin impuestos congelados."}}},"Sale":{"type":"object","description":"Venta. Ingreso neto = total - tax - tip_amount.","required":["object","id","status","document_kind","payment_method","customer_id","cash_session_id","subtotal","discount","discount_percent","tax","tip_amount","total","tax_breakdown","notes","table_label","items","invoices","occurred_at","created_at","updated_at"],"properties":{"object":{"const":"sale"},"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"Estado tal como lo registró el POS (completed, cancelled, open, pending…)."},"document_kind":{"type":"string","enum":["pos","invoice"],"description":"Documento que pidió el POS al cobrar."},"payment_method":{"type":"string","description":"Medio de pago tal como lo registró el POS (CASH, CARD, NEQUI…)."},"customer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"cash_session_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"subtotal":{"type":"integer","description":"Suma de las líneas a precio de lista (antes de los descuentos), impuestos incluidos."},"discount":{"type":"integer","description":"Suma de los `discount_amount` de las líneas (descuentos del cajero)."},"discount_percent":{"type":"number"},"tax":{"type":"integer","description":"Parte del total que es impuesto."},"tip_amount":{"type":"integer","description":"Propina. Nunca es base gravable."},"total":{"type":"integer","description":"subtotal - discount + tip_amount."},"tax_breakdown":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/TaxBreakdownEntry"}},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"table_label":{"anyOf":[{"type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"$ref":"#/components/schemas/SaleItem"}},"invoices":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceSummary"}},"occurred_at":{"type":"string","format":"date-time","description":"Cuando se registró la venta en la caja (reloj de la caja). En ventas sincronizadas antes del 28-sep-2026 es la hora de llegada."},"created_at":{"type":"string","format":"date-time","description":"Cuando la venta llegó al servidor (una caja sin conexión la sube después)."},"updated_at":{"type":"string","format":"date-time"}}},"Invoice":{"type":"object","description":"Documento de una venta (electrónico ante la DIAN o interno). El PDF/XML no se publican por la API en v1.","required":["object","id","sale_id","document_type","type_document_id","status","dian_status","dian_message","document_reason","prefix","number","cufe","subtotal","tax","total","issued_at","created_at","updated_at"],"properties":{"object":{"const":"invoice"},"id":{"type":"string","format":"uuid"},"sale_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"document_type":{"$ref":"#/components/schemas/DocumentType"},"type_document_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Código del tipo de documento DIAN (1, 15, 26)."},"status":{"type":"string","description":"pending, issued, rejected, emission_failed, annulled."},"dian_status":{"anyOf":[{"type":"string"},{"type":"null"}]},"dian_message":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Mensaje de la DIAN; solo cuando el documento fue emitido o rechazado."},"document_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Por qué se eligió este tipo de documento."},"prefix":{"anyOf":[{"type":"string"},{"type":"null"}]},"number":{"type":"integer"},"cufe":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"CUFE (factura) o CUDE (documento POS)."},"subtotal":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"tax":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"total":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"issued_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"QuoteItem":{"type":"object","description":"Línea de una cotización.","required":["object","id","product_id","variant_id","item_kind","description","quantity","unit_price","subtotal","tax_class","taxes","note"],"properties":{"object":{"const":"quote_item"},"id":{"type":"string","format":"uuid"},"product_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"variant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"item_kind":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"unit_price":{"type":"integer","description":"Con impuestos porcentuales incluidos."},"subtotal":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"tax_class":{"type":"string"},"taxes":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/LineTax"}},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"Quote":{"type":"object","description":"Cotización.","required":["object","id","number","status","customer_id","converted_sale_id","subtotal","discount","tax","total","tax_breakdown","notes","payment_link","expires_at","sent_at","items","created_at","updated_at"],"properties":{"object":{"const":"quote"},"id":{"type":"string","format":"uuid"},"number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"COT-XXXX; solo existe cuando la cotización se envió."},"status":{"type":"string","description":"draft, sent, accepted, rejected, expired, converted. El vencimiento lo aplica la app al leer: compara con `expires_at`."},"customer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"converted_sale_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"subtotal":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"discount":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"tax":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"total":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"tax_breakdown":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/TaxBreakdownEntry"}},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_link":{"anyOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"items":{"type":"array","items":{"$ref":"#/components/schemas/QuoteItem"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"CashMovement":{"type":"object","description":"Entrada o salida manual de efectivo del cajón.","required":["object","id","type","amount","reason","created_at"],"properties":{"object":{"const":"cash_movement"},"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["in","out"]},"amount":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"}}},"CashSession":{"type":"object","description":"Turno de caja con sus movimientos de efectivo.","required":["object","id","status","terminal_name","opening_cash","expected_cash","closing_cash","opened_at","closed_at","movements","created_at","updated_at"],"properties":{"object":{"const":"cash_session"},"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"open, closed, suspended."},"terminal_name":{"type":"string","description":"Nombre de la caja (\"Caja 01\")."},"opening_cash":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"expected_cash":{"anyOf":[{"type":"integer","description":"Lo que la app calculó que debía haber al cerrar."},{"type":"null"}]},"closing_cash":{"anyOf":[{"type":"integer","description":"Lo que se contó al cerrar."},{"type":"null"}]},"opened_at":{"type":"string","format":"date-time"},"closed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"movements":{"type":"array","items":{"$ref":"#/components/schemas/CashMovement"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"DailySalesDay":{"type":"object","description":"Totales de un día (hora de Bogotá).","required":["date","sales_count","subtotal","discount","tax","tip_amount","total"],"properties":{"date":{"type":"string","format":"date"},"sales_count":{"type":"integer","description":"Número de ventas completadas."},"subtotal":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"discount":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"tax":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"tip_amount":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"total":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."}}},"DailySalesReport":{"type":"object","description":"Ventas completadas por día calendario de Bogotá. Una venta cuenta en el día en que se registró en la caja (`occurred_at`); las sincronizadas antes del 28-sep-2026 cuentan en el día en que llegaron al servidor.","required":["object","timezone","currency","from","to","days","totals"],"properties":{"object":{"const":"daily_sales_report"},"timezone":{"const":"America/Bogota"},"currency":{"const":"COP"},"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"days":{"type":"array","items":{"$ref":"#/components/schemas/DailySalesDay"},"description":"Un elemento por día del rango, incluidos los días sin ventas (en cero)."},"totals":{"type":"object","required":["sales_count","subtotal","discount","tax","tip_amount","total"],"properties":{"sales_count":{"type":"integer","description":"Número de ventas completadas."},"subtotal":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"discount":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"tax":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"tip_amount":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."},"total":{"type":"integer","description":"Pesos colombianos (COP), entero sin decimales."}}}}},"Event":{"type":"object","description":"Evento del registro de webhooks. Sirve para reconciliar entregas perdidas.","required":["object","id","type","created_at","data"],"properties":{"object":{"const":"event"},"id":{"type":"string","format":"uuid"},"type":{"type":"string","description":"Tipo de evento, por ejemplo `sale.completed`."},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object","required":["object"],"properties":{"object":{"type":"object","description":"El objeto (venta, producto…) tal como era cuando ocurrió el evento."}}}}},"CategoryCreate":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":1000},"sort_order":{"type":"integer","minimum":0,"maximum":100000}}},"CategoryUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"name":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":1000},"sort_order":{"type":"integer","minimum":0,"maximum":100000}}},"ProductCreate":{"type":"object","additionalProperties":false,"required":["name","base_price"],"properties":{"name":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":5000},"description_short":{"type":"string","maxLength":300},"sku":{"type":"string","maxLength":60},"category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"base_price":{"type":"integer","minimum":0,"maximum":10000000000,"description":"Precio base en pesos."},"final_price":{"type":"integer","minimum":0,"maximum":10000000000,"description":"Precio al que vende la caja. Si no se envía, es igual a base_price."},"percent_discount":{"type":"number","minimum":0,"maximum":100},"tax_class":{"type":"string","enum":["standard","reduced_5","excluded","exempt","service_19","event_package","bag","passthrough"],"default":"standard","description":"Clase fiscal del ítem. `standard` hereda del perfil fiscal del negocio."},"active":{"type":"boolean","default":true},"sellable":{"type":"boolean","default":true,"description":"`false` = insumo que no se vende solo."},"base_unit":{"type":"string","enum":["und","g","kg","lb","oz","ml","l","doc"],"default":"und"},"sold_by_weight":{"type":"boolean","default":false,"description":"Requiere base_unit g, kg o lb."},"initial_stock":{"type":"integer","minimum":1,"maximum":1000000000,"description":"Crea además un movimiento de entrada con este stock."},"warehouse_id":{"type":"string","format":"uuid","description":"Bodega del stock inicial. Por defecto, la bodega predeterminada."}}},"ProductUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"description":"El stock no se edita aquí: usa POST /inventory/movements. La unidad, la venta por peso y el tipo de producto tampoco (cambian el significado del stock existente).","properties":{"name":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":5000},"description_short":{"type":"string","maxLength":300},"sku":{"type":"string","maxLength":60},"category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"base_price":{"type":"integer","minimum":0,"maximum":10000000000,"description":"Si cambias base_price sin enviar final_price, final_price toma el mismo valor."},"final_price":{"type":"integer","minimum":0,"maximum":10000000000,"description":"Precio al que vende la caja."},"percent_discount":{"type":"number","minimum":0,"maximum":100},"tax_class":{"type":"string","enum":["standard","reduced_5","excluded","exempt","service_19","event_package","bag","passthrough"]},"active":{"type":"boolean"},"sellable":{"type":"boolean"}}},"VariantUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"label":{"type":"string","maxLength":120},"sku":{"type":"string","maxLength":60,"description":"Único por cuenta."},"base_price":{"type":"integer","minimum":0,"maximum":10000000000,"description":"Si cambias base_price sin enviar final_price, final_price toma el mismo valor."},"final_price":{"type":"integer","minimum":0,"maximum":10000000000,"description":"Precio al que vende la caja."},"percent_discount":{"type":"number","minimum":0,"maximum":100},"active":{"type":"boolean"}}},"CustomerCreate":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","maxLength":120},"last_name":{"type":"string","maxLength":120},"phone":{"type":"string","maxLength":30},"email":{"anyOf":[{"type":"string","format":"email","maxLength":200},{"type":"null"}]},"person_type":{"type":"string","enum":["person","company"],"default":"person"},"document_type":{"type":"string","enum":["CC","TI","NIT","CE","PASAPORTE"],"default":"CC"},"document_number":{"type":"string","maxLength":30},"contact_channel":{"type":"string","enum":["none","store","whatsapp","instagram","website","referral"],"default":"none"}}},"CustomerUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"name":{"type":"string","maxLength":120},"last_name":{"type":"string","maxLength":120},"phone":{"type":"string","maxLength":30},"email":{"anyOf":[{"type":"string","format":"email","maxLength":200},{"type":"null"}]},"person_type":{"type":"string","enum":["person","company"],"default":"person"},"document_type":{"type":"string","enum":["CC","TI","NIT","CE","PASAPORTE"],"default":"CC"},"document_number":{"type":"string","maxLength":30},"contact_channel":{"type":"string","enum":["none","store","whatsapp","instagram","website","referral"],"default":"none"}}},"StockMovementCreate":{"type":"object","additionalProperties":false,"required":["product_id","type","quantity"],"properties":{"product_id":{"type":"string","format":"uuid"},"variant_id":{"type":"string","format":"uuid","description":"Obligatorio si el producto tiene variantes: el movimiento es de esa variante."},"warehouse_id":{"type":"string","format":"uuid","description":"Por defecto, la bodega predeterminada (o la única bodega activa)."},"type":{"type":"string","enum":["in","out"],"description":"`in` suma, `out` resta."},"quantity":{"type":"number","exclusiveMinimum":0,"maximum":1000000000,"description":"En la unidad base del producto. Entero, salvo en productos que se venden por peso (`sold_by_weight`), que aceptan decimales (0.375 kg)."},"reason":{"type":"string","maxLength":200,"description":"Motivo visible en el historial. Por defecto \"Movimiento vía API\"."},"reference":{"type":"string","maxLength":100,"description":"Tu referencia (orden de compra, pedido…)."},"unit_cost":{"type":"number","exclusiveMinimum":0,"maximum":1000000000,"description":"Solo en entradas (`type: in`): lo que costó cada unidad base. Alimenta el costo promedio ponderado de la cuenta. Si no lo conoces, no lo envíes (nunca 0). Una salida sale siempre al costo promedio."}}},"StockCountCreate":{"type":"object","additionalProperties":false,"required":["product_id","counted_quantity"],"properties":{"product_id":{"type":"string","format":"uuid"},"variant_id":{"type":"string","format":"uuid","description":"Obligatorio si el producto tiene variantes."},"warehouse_id":{"type":"string","format":"uuid","description":"Por defecto, la bodega predeterminada (o la única bodega activa)."},"counted_quantity":{"type":"number","minimum":0,"maximum":1000000000,"description":"Lo que hay físicamente, en la unidad base del producto. Entero, salvo en productos que se venden por peso (`sold_by_weight`), que aceptan decimales."},"counted_at":{"type":"string","format":"date-time","description":"CUÁNDO se contó (no cuándo se envía), ISO 8601 con zona. Nunca en el futuro. Por defecto, ahora. Las ventas ocurridas después se suman encima."},"note":{"type":"string","maxLength":500,"description":"Nota visible en el historial del conteo."}}},"DeletedObject":{"type":"object","additionalProperties":false,"required":["id","object","deleted"],"description":"Lo que responde un DELETE: el objeto ya no existe, así que solo se devuelve su id y su tipo.","properties":{"id":{"type":"string","format":"uuid"},"object":{"type":"string","enum":["product","variant","category","customer"],"description":"Tipo del objeto eliminado. Una variante es `variant`."},"deleted":{"const":true}}},"DeletedWebhookObject":{"type":"object","additionalProperties":false,"required":["id","object","deleted","deleted_at"],"description":"`data.object` de `product.deleted`, `category.deleted` y `customer.deleted`: el objeto ya no existe, así que solo viaja su id, su tipo y cuándo se eliminó.","properties":{"id":{"type":"string","format":"uuid"},"object":{"type":"string","enum":["product","category","customer"]},"deleted":{"const":true},"deleted_at":{"type":"string","format":"date-time"}}}}},"paths":{"/me":{"get":{"tags":["Cuenta"],"operationId":"getMe","summary":"Cuenta, API key y frescura de los datos","description":"Cualquier API key válida.","x-scope":null,"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products":{"get":{"tags":["Productos"],"operationId":"listProducts","summary":"Listar productos","description":"Productos con sus variantes, del más reciente al más antiguo.\n\nPermiso requerido: `products:read`.","x-scope":"products:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}},{"name":"active","in":"query","description":"Solo activos (`true`) o inactivos (`false`).","schema":{"type":"boolean"}},{"name":"category_id","in":"query","description":"Productos de esa categoría.","schema":{"type":"string","format":"uuid"}},{"name":"sku","in":"query","description":"Coincidencia exacta con el SKU del producto o de cualquiera de sus variantes.","schema":{"type":"string","maxLength":100}},{"name":"q","in":"query","description":"Busca en el nombre (sin distinguir mayúsculas).","schema":{"type":"string","minLength":2,"maxLength":100}},{"name":"include_deleted","in":"query","description":"Si es `true`, incluye los registros eliminados (con `deleted_at`).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Productos"],"operationId":"createProduct","summary":"Crear producto","description":"Crea un producto sin variantes. Con `initial_stock` registra además un movimiento de entrada en la bodega indicada. El cambio llega a las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse).\n\nPermiso requerido: `products:write`.","x-scope":"products:write","security":[{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Obligatorio en todo POST. Un valor único por operación (p. ej. un UUID); reutilízalo solo para reintentar la MISMA operación. Válido 24 h.","schema":{"type":"string","maxLength":255,"pattern":"^[A-Za-z0-9_\\-:.]{1,255}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCreate"}}}},"responses":{"201":{"description":"Creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (CONFLICT, SKU_ALREADY_EXISTS, IDEMPOTENCY_IN_PROGRESS, NO_WAREHOUSE, DEVICES_OUTDATED, INSUFFICIENT_STOCK con `available`, STOCK_MODE_LEGACY).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Regla de negocio o idempotencia (IDEMPOTENCY_KEY_REUSED, COMPOSITE_STOCK_UNSUPPORTED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/{id}":{"get":{"tags":["Productos"],"operationId":"getProduct","summary":"Obtener un producto","description":"Permiso requerido: `products:read`.","x-scope":"products:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"include_deleted","in":"query","description":"Si es `true`, incluye los registros eliminados (con `deleted_at`).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Productos"],"operationId":"updateProduct","summary":"Editar producto","description":"Cambia nombre, precios, categoría, SKU, clase fiscal o estado. El cambio viaja a las cajas SIN stock, unidad ni tipo: cada caja conserva los suyos, así que nunca toca el inventario. Requiere que todas las cajas del negocio tengan la versión de Posdata que lo soporta; si alguna no la tiene responde 409 DEVICES_OUTDATED con la lista y no modifica nada. El cambio llega a las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse).\n\nPermiso requerido: `products:write`.","x-scope":"products:write","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdate"}}}},"responses":{"200":{"description":"Actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (CONFLICT, SKU_ALREADY_EXISTS, IDEMPOTENCY_IN_PROGRESS, NO_WAREHOUSE, DEVICES_OUTDATED, INSUFFICIENT_STOCK con `available`, STOCK_MODE_LEGACY).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Regla de negocio o idempotencia (IDEMPOTENCY_KEY_REUSED, COMPOSITE_STOCK_UNSUPPORTED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Productos"],"operationId":"deleteProduct","summary":"Eliminar producto","description":"Elimina un producto **y sus variantes** y emite el webhook `product.deleted`. Si solo quieres dejar de venderlo, es mejor `PATCH /products/{id}` con `active: false`. Un producto que se usa como insumo en la receta de otro producto no se elimina: primero hay que quitarlo de esas recetas (o eliminar esos productos) en Posdata.\n\nEs **irreversible** y es el mismo borrado que hace una caja: el registro queda marcado como eliminado (lo ves con `include_deleted=true`) y desaparece de las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse). Las ventas, documentos y movimientos que lo usaron no cambian.\n\nSin `Idempotency-Key`: si repites la llamada, la segunda responde 404 `NOT_FOUND` (ya no existe).\n\nVentas, documentos electrónicos, turnos y movimientos de caja, movimientos y conteos de stock y bodegas no se pueden eliminar por la API: son el historial contable y fiscal del negocio.\n\nPermiso requerido: `products:delete`.","x-scope":"products:delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Eliminado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedObject"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta o ya estaba eliminado (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"PRODUCT_IN_USE: el producto es insumo de una o más recetas. `recipes` lista cada producto que lo usa (`[{ product_id, name }]`). No se eliminó nada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/categories":{"get":{"tags":["Productos"],"operationId":"listCategories","summary":"Listar categorías","description":"Permiso requerido: `products:read`.","x-scope":"products:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}},{"name":"include_deleted","in":"query","description":"Si es `true`, incluye los registros eliminados (con `deleted_at`).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Productos"],"operationId":"createCategory","summary":"Crear categoría","description":"El cambio llega a las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse).\n\nPermiso requerido: `products:write`.","x-scope":"products:write","security":[{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Obligatorio en todo POST. Un valor único por operación (p. ej. un UUID); reutilízalo solo para reintentar la MISMA operación. Válido 24 h.","schema":{"type":"string","maxLength":255,"pattern":"^[A-Za-z0-9_\\-:.]{1,255}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryCreate"}}}},"responses":{"201":{"description":"Creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (CONFLICT, SKU_ALREADY_EXISTS, IDEMPOTENCY_IN_PROGRESS, NO_WAREHOUSE, DEVICES_OUTDATED, INSUFFICIENT_STOCK con `available`, STOCK_MODE_LEGACY).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Regla de negocio o idempotencia (IDEMPOTENCY_KEY_REUSED, COMPOSITE_STOCK_UNSUPPORTED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/categories/{id}":{"get":{"tags":["Productos"],"operationId":"getCategory","summary":"Obtener una categoría","description":"Permiso requerido: `products:read`.","x-scope":"products:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"include_deleted","in":"query","description":"Si es `true`, incluye los registros eliminados (con `deleted_at`).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Productos"],"operationId":"updateCategory","summary":"Editar categoría","description":"El cambio llega a las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse).\n\nPermiso requerido: `products:write`.","x-scope":"products:write","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryUpdate"}}}},"responses":{"200":{"description":"Actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (CONFLICT, SKU_ALREADY_EXISTS, IDEMPOTENCY_IN_PROGRESS, NO_WAREHOUSE, DEVICES_OUTDATED, INSUFFICIENT_STOCK con `available`, STOCK_MODE_LEGACY).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Regla de negocio o idempotencia (IDEMPOTENCY_KEY_REUSED, COMPOSITE_STOCK_UNSUPPORTED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Productos"],"operationId":"deleteCategory","summary":"Eliminar categoría","description":"Elimina una categoría vacía y emite el webhook `category.deleted`. Si todavía tiene productos (activos o inactivos), muévelos antes a otra categoría con `PATCH /products/{id}`.\n\nEs **irreversible** y es el mismo borrado que hace una caja: el registro queda marcado como eliminado (lo ves con `include_deleted=true`) y desaparece de las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse). Las ventas, documentos y movimientos que lo usaron no cambian.\n\nSin `Idempotency-Key`: si repites la llamada, la segunda responde 404 `NOT_FOUND` (ya no existe).\n\nVentas, documentos electrónicos, turnos y movimientos de caja, movimientos y conteos de stock y bodegas no se pueden eliminar por la API: son el historial contable y fiscal del negocio.\n\nPermiso requerido: `products:delete`.","x-scope":"products:delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Eliminado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedObject"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta o ya estaba eliminado (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"CATEGORY_IN_USE: la categoría tiene productos. `products` dice cuántos. No se eliminó nada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers":{"get":{"tags":["Clientes"],"operationId":"listCustomers","summary":"Listar clientes","description":"Permiso requerido: `customers:read`.","x-scope":"customers:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}},{"name":"email","in":"query","description":"Coincidencia exacta, sin distinguir mayúsculas.","schema":{"type":"string","maxLength":254}},{"name":"document_number","in":"query","description":"Número de documento, coincidencia exacta.","schema":{"type":"string","maxLength":40}},{"name":"q","in":"query","description":"Busca en nombre, apellido, email, teléfono y documento.","schema":{"type":"string","minLength":2,"maxLength":100}},{"name":"include_deleted","in":"query","description":"Si es `true`, incluye los registros eliminados (con `deleted_at`).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Clientes"],"operationId":"createCustomer","summary":"Crear cliente","description":"El cambio llega a las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse).\n\nPermiso requerido: `customers:write`.","x-scope":"customers:write","security":[{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Obligatorio en todo POST. Un valor único por operación (p. ej. un UUID); reutilízalo solo para reintentar la MISMA operación. Válido 24 h.","schema":{"type":"string","maxLength":255,"pattern":"^[A-Za-z0-9_\\-:.]{1,255}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerCreate"}}}},"responses":{"201":{"description":"Creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (CONFLICT, SKU_ALREADY_EXISTS, IDEMPOTENCY_IN_PROGRESS, NO_WAREHOUSE, DEVICES_OUTDATED, INSUFFICIENT_STOCK con `available`, STOCK_MODE_LEGACY).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Regla de negocio o idempotencia (IDEMPOTENCY_KEY_REUSED, COMPOSITE_STOCK_UNSUPPORTED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers/{id}":{"get":{"tags":["Clientes"],"operationId":"getCustomer","summary":"Obtener un cliente","description":"Permiso requerido: `customers:read`.","x-scope":"customers:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"include_deleted","in":"query","description":"Si es `true`, incluye los registros eliminados (con `deleted_at`).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Clientes"],"operationId":"updateCustomer","summary":"Editar cliente","description":"El cambio llega a las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse).\n\nPermiso requerido: `customers:write`.","x-scope":"customers:write","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerUpdate"}}}},"responses":{"200":{"description":"Actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (CONFLICT, SKU_ALREADY_EXISTS, IDEMPOTENCY_IN_PROGRESS, NO_WAREHOUSE, DEVICES_OUTDATED, INSUFFICIENT_STOCK con `available`, STOCK_MODE_LEGACY).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Regla de negocio o idempotencia (IDEMPOTENCY_KEY_REUSED, COMPOSITE_STOCK_UNSUPPORTED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Clientes"],"operationId":"deleteCustomer","summary":"Eliminar cliente","description":"Elimina un cliente sin ventas y emite el webhook `customer.deleted`. Un cliente con ventas registradas no se elimina: esas ventas quedarían sin cliente; si sus datos están mal, corrígelos con `PATCH /customers/{id}`.\n\nEs **irreversible** y es el mismo borrado que hace una caja: el registro queda marcado como eliminado (lo ves con `include_deleted=true`) y desaparece de las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse). Las ventas, documentos y movimientos que lo usaron no cambian.\n\nSin `Idempotency-Key`: si repites la llamada, la segunda responde 404 `NOT_FOUND` (ya no existe).\n\nVentas, documentos electrónicos, turnos y movimientos de caja, movimientos y conteos de stock y bodegas no se pueden eliminar por la API: son el historial contable y fiscal del negocio.\n\nPermiso requerido: `customers:delete`.","x-scope":"customers:delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Eliminado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedObject"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta o ya estaba eliminado (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"CUSTOMER_HAS_SALES: el cliente tiene ventas registradas. `sales` dice cuántas. No se eliminó nada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/warehouses":{"get":{"tags":["Inventario"],"operationId":"listWarehouses","summary":"Listar bodegas","description":"Permiso requerido: `inventory:read`.","x-scope":"inventory:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Warehouse"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/warehouses/{id}":{"get":{"tags":["Inventario"],"operationId":"getWarehouse","summary":"Obtener una bodega","description":"Permiso requerido: `inventory:read`.","x-scope":"inventory:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Warehouse"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory/movements":{"get":{"tags":["Inventario"],"operationId":"listStockMovements","summary":"Listar movimientos de inventario","description":"Permiso requerido: `inventory:read`.","x-scope":"inventory:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}},{"name":"product_id","in":"query","description":"Movimientos de ese producto.","schema":{"type":"string","format":"uuid"}},{"name":"warehouse_id","in":"query","description":"Movimientos de esa bodega.","schema":{"type":"string","format":"uuid"}},{"name":"type","in":"query","description":"Tipo de movimiento, coincidencia exacta.","schema":{"type":"string","maxLength":40}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/StockMovement"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Inventario"],"operationId":"createStockMovement","summary":"Registrar movimiento de stock","description":"Suma (`in`) o resta (`out`) stock de un producto o de una de sus variantes (`variant_id`). Una salida `out` es atómica: 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 409 INSUFFICIENT_STOCK con `available` (lo que sí puedes sacar) y no registra nada; con varias peticiones a la vez por la última unidad, solo una gana. Una entrada `in` no tiene tope y puede declarar su costo (`unit_cost`), que alimenta el costo promedio de la cuenta. Los productos que se arman con receta y los packs o combos no tienen stock propio (COMPOSITE_STOCK_UNSUPPORTED). Mientras la cuenta no haya pasado al stock en la nube (las cajas aún en una versión anterior), el stock de variantes responde 409 STOCK_MODE_LEGACY. El cambio llega a las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse).\n\nPermiso requerido: `inventory:write`.","x-scope":"inventory:write","security":[{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Obligatorio en todo POST. Un valor único por operación (p. ej. un UUID); reutilízalo solo para reintentar la MISMA operación. Válido 24 h.","schema":{"type":"string","maxLength":255,"pattern":"^[A-Za-z0-9_\\-:.]{1,255}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockMovementCreate"}}}},"responses":{"201":{"description":"Creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockMovement"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (CONFLICT, SKU_ALREADY_EXISTS, IDEMPOTENCY_IN_PROGRESS, NO_WAREHOUSE, DEVICES_OUTDATED, INSUFFICIENT_STOCK con `available`, STOCK_MODE_LEGACY).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Regla de negocio o idempotencia (IDEMPOTENCY_KEY_REUSED, COMPOSITE_STOCK_UNSUPPORTED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory/levels":{"get":{"tags":["Inventario"],"operationId":"listStockLevels","summary":"Listar el stock por bodega","description":"Stock oficial por (bodega, producto, variante) y lo que la API puede comprometer (`available`). Solo cuando la cuenta lleva el stock en la nube (todas sus cajas con la versión nueva de Posdata); antes responde 409 STOCK_MODE_LEGACY.\n\nPermiso requerido: `inventory:read`.","x-scope":"inventory:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}},{"name":"product_id","in":"query","description":"Niveles de ese producto.","schema":{"type":"string","format":"uuid"}},{"name":"variant_id","in":"query","description":"Niveles de esa variante.","schema":{"type":"string","format":"uuid"}},{"name":"warehouse_id","in":"query","description":"Niveles de esa bodega.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/StockLevel"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"STOCK_MODE_LEGACY: la cuenta todavía no lleva el stock en la nube (sus cajas aún en una versión anterior de Posdata).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory/movements/{id}":{"get":{"tags":["Inventario"],"operationId":"getStockMovement","summary":"Obtener un movimiento de inventario","description":"Permiso requerido: `inventory:read`.","x-scope":"inventory:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockMovement"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory/kardex":{"get":{"tags":["Inventario"],"operationId":"getInventoryKardex","summary":"Kardex de un producto","description":"El libro de un producto con saldo corrido; con `inventory:costs` también el costo y el valor. Solo cuando la cuenta lleva el stock en la nube (todas sus cajas con la versión nueva de Posdata); antes responde 409 STOCK_MODE_LEGACY.\n\nPermiso requerido: `inventory:read`.","x-scope":"inventory:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"product_id","in":"query","description":"El producto (obligatorio).","schema":{"type":"string","format":"uuid"}},{"name":"warehouse_id","in":"query","description":"Solo las filas de esa bodega (el saldo total sigue siendo el del producto).","schema":{"type":"string","format":"uuid"}},{"name":"variant_id","in":"query","description":"Solo las filas de esa variante.","schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","description":"Desde (instante ISO 8601 con zona). Los saldos ya incluyen lo anterior.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Hasta (instante ISO 8601 con zona).","schema":{"type":"string","format":"date-time"}},{"name":"type","in":"query","description":"Solo ese tipo de fila.","schema":{"type":"string","enum":["in","out","count","cost"]}},{"name":"order","in":"query","description":"Orden cronológico.","schema":{"type":"string","enum":["asc","desc"],"default":"asc"}},{"name":"page","in":"query","description":"Página (empieza en 1).","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","description":"Filas por página (máximo 200).","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryKardex"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"STOCK_MODE_LEGACY: la cuenta todavía no lleva el stock en la nube (sus cajas aún en una versión anterior de Posdata).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory/valuation":{"get":{"tags":["Inventario"],"operationId":"getInventoryValuation","summary":"Valor del inventario","description":"El valor del inventario hoy o a una fecha pasada. Solo cuando la cuenta lleva el stock en la nube (todas sus cajas con la versión nueva de Posdata); antes responde 409 STOCK_MODE_LEGACY.\n\nPermiso requerido: `inventory:costs`.","x-scope":"inventory:costs","security":[{"bearerAuth":[]}],"parameters":[{"name":"at","in":"query","description":"La fecha de corte (instante ISO 8601 con zona). Por defecto, ahora.","schema":{"type":"string","format":"date-time"}},{"name":"warehouse_id","in":"query","description":"Solo esa bodega.","schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","description":"Página (empieza en 1).","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","description":"Filas por página (máximo 200).","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryValuation"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"STOCK_MODE_LEGACY: la cuenta todavía no lleva el stock en la nube (sus cajas aún en una versión anterior de Posdata).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sales":{"get":{"tags":["Ventas"],"operationId":"listSales","summary":"Listar ventas","description":"Permiso requerido: `sales:read`.","x-scope":"sales:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}},{"name":"status","in":"query","description":"Estado exacto, por ejemplo `completed`.","schema":{"type":"string","maxLength":40}},{"name":"customer_id","in":"query","description":"Ventas de ese cliente.","schema":{"type":"string","format":"uuid"}},{"name":"document_kind","in":"query","description":"Tipo de documento pedido.","schema":{"type":"string","enum":["pos","invoice"]}},{"name":"occurred_since","in":"query","description":"Ventas registradas en la caja desde este instante (incluye). ISO 8601 con zona horaria.","schema":{"type":"string","format":"date-time"}},{"name":"occurred_until","in":"query","description":"Ventas registradas en la caja antes de este instante (excluye).","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Sale"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sales/{id}":{"get":{"tags":["Ventas"],"operationId":"getSale","summary":"Obtener una venta","description":"Permiso requerido: `sales:read`.","x-scope":"sales:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Sale"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/invoices":{"get":{"tags":["Facturación"],"operationId":"listInvoices","summary":"Listar documentos","description":"Permiso requerido: `invoices:read`.","x-scope":"invoices:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}},{"name":"sale_id","in":"query","description":"Documentos de esa venta.","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","description":"Estado exacto.","schema":{"type":"string","maxLength":40}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/invoices/{id}":{"get":{"tags":["Facturación"],"operationId":"getInvoice","summary":"Obtener un documento","description":"Permiso requerido: `invoices:read`.","x-scope":"invoices:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invoice"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quotes":{"get":{"tags":["Cotizaciones"],"operationId":"listQuotes","summary":"Listar cotizaciones","description":"Permiso requerido: `quotes:read`.","x-scope":"quotes:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}},{"name":"status","in":"query","description":"Estado exacto.","schema":{"type":"string","maxLength":40}},{"name":"customer_id","in":"query","description":"Cotizaciones de ese cliente.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Quote"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quotes/{id}":{"get":{"tags":["Cotizaciones"],"operationId":"getQuote","summary":"Obtener una cotización","description":"Permiso requerido: `quotes:read`.","x-scope":"quotes:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/cash-sessions":{"get":{"tags":["Caja"],"operationId":"listCashSessions","summary":"Listar turnos de caja","description":"Permiso requerido: `cash:read`.","x-scope":"cash:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"updated_since","in":"query","description":"ISO 8601 con zona horaria. Para sincronización incremental.","schema":{"type":"string","format":"date-time"}},{"name":"status","in":"query","description":"open, closed o suspended.","schema":{"type":"string","maxLength":40}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/CashSession"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/cash-sessions/{id}":{"get":{"tags":["Caja"],"operationId":"getCashSession","summary":"Obtener un turno de caja","description":"Permiso requerido: `cash:read`.","x-scope":"cash:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashSession"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/daily-sales":{"get":{"tags":["Reportes"],"operationId":"getDailySales","summary":"Ventas por día","description":"Solo ventas con estado `completed`. Rango inclusivo de hasta 92 días.\n\nPermiso requerido: `reports:read`.","x-scope":"reports:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"from","in":"query","required":true,"description":"Primer día (YYYY-MM-DD), inclusive.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":true,"description":"Último día (YYYY-MM-DD), inclusive.","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailySalesReport"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/events":{"get":{"tags":["Eventos"],"operationId":"listEvents","summary":"Listar eventos","description":"Permiso requerido: `events:read`.","x-scope":"events:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"starting_after","in":"query","description":"El `next_cursor` de la página anterior, tal cual.","schema":{"type":"string"}},{"name":"created_since","in":"query","description":"ISO 8601 con zona horaria. Incluye.","schema":{"type":"string","format":"date-time"}},{"name":"created_until","in":"query","description":"ISO 8601 con zona horaria. Excluye.","schema":{"type":"string","format":"date-time"}},{"name":"type","in":"query","description":"Tipo exacto, por ejemplo `sale.completed`.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/events/{id}":{"get":{"tags":["Eventos"],"operationId":"getEvent","summary":"Obtener un evento","description":"Permiso requerido: `events:read`.","x-scope":"events:read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/{id}/variants/{variantId}":{"patch":{"tags":["Productos"],"operationId":"updateVariant","summary":"Editar variante","description":"Cambia etiqueta, SKU, precios o estado de una variante (nunca su stock). Responde el producto completo. Misma condición de versión de las cajas que editar un producto (409 DEVICES_OUTDATED). El cambio llega a las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse).\n\nPermiso requerido: `products:write`.","x-scope":"products:write","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"variantId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VariantUpdate"}}}},"responses":{"200":{"description":"Actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (CONFLICT, SKU_ALREADY_EXISTS, IDEMPOTENCY_IN_PROGRESS, NO_WAREHOUSE, DEVICES_OUTDATED, INSUFFICIENT_STOCK con `available`, STOCK_MODE_LEGACY).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Regla de negocio o idempotencia (IDEMPOTENCY_KEY_REUSED, COMPOSITE_STOCK_UNSUPPORTED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Productos"],"operationId":"deleteVariant","summary":"Eliminar variante","description":"Elimina una variante de un producto (como en el formulario de variantes de la app, sin más reglas). El producto sigue existiendo; su stock deja de sumar el de la variante eliminada. Emite el webhook `product.updated` con el producto ya sin esa variante (lo mismo que editar una variante).\n\nEs **irreversible** y es el mismo borrado que hace una caja: el registro queda marcado como eliminado (lo ves con `include_deleted=true`) y desaparece de las cajas del negocio por su sincronización normal (en segundos si están en línea; si están sin conexión, al reconectarse). Las ventas, documentos y movimientos que lo usaron no cambian.\n\nSin `Idempotency-Key`: si repites la llamada, la segunda responde 404 `NOT_FOUND` (ya no existe).\n\nVentas, documentos electrónicos, turnos y movimientos de caja, movimientos y conteos de stock y bodegas no se pueden eliminar por la API: son el historial contable y fiscal del negocio.\n\nPermiso requerido: `products:delete`.","x-scope":"products:delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"variantId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Eliminado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedObject"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en esta cuenta o ya estaba eliminado (NOT_FOUND).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory/counts":{"post":{"tags":["Inventario"],"operationId":"createStockCount","summary":"Registrar un conteo de inventario","description":"Registra lo que hay físicamente en una bodega en un instante (`counted_at`): el stock oficial pasa a ser esa cantidad y las ventas ocurridas después del conteo se suman encima, nunca se pierden. Un conteo más viejo que el último registrado queda solo como historial (`status: historical`). Solo cuando la cuenta ya lleva el stock en la nube; si no, 409 STOCK_MODE_LEGACY. Emite el webhook `inventory.count.created`.\n\nPermiso requerido: `inventory:write`.","x-scope":"inventory:write","security":[{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Obligatorio en todo POST. Un valor único por operación (p. ej. un UUID); reutilízalo solo para reintentar la MISMA operación. Válido 24 h.","schema":{"type":"string","maxLength":255,"pattern":"^[A-Za-z0-9_\\-:.]{1,255}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockCountCreate"}}}},"responses":{"201":{"description":"Creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockCount"}}}},"400":{"description":"Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (CONFLICT, SKU_ALREADY_EXISTS, IDEMPOTENCY_IN_PROGRESS, NO_WAREHOUSE, DEVICES_OUTDATED, INSUFFICIENT_STOCK con `available`, STOCK_MODE_LEGACY).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Regla de negocio o idempotencia (IDEMPOTENCY_KEY_REUSED, COMPOSITE_STOCK_UNSUPPORTED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de peticiones (RATE_LIMITED). Respeta Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"sale.created":{"post":{"operationId":"webhookSaleCreated","summary":"Venta creada","description":"Una venta nueva llegó a la nube (la subió una caja). **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"sale.created"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Sale"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"sale.updated":{"post":{"operationId":"webhookSaleUpdated","summary":"Venta actualizada","description":"Una caja subió un cambio de una venta existente. Puede repetirse: trátalo como «vuelve a leer este objeto».\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"sale.updated"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Sale"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"sale.completed":{"post":{"operationId":"webhookSaleCompleted","summary":"Venta completada","description":"La venta quedó completada. **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"sale.completed"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Sale"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"sale.cancelled":{"post":{"operationId":"webhookSaleCancelled","summary":"Venta anulada","description":"La venta quedó anulada. **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"sale.cancelled"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Sale"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"product.created":{"post":{"operationId":"webhookProductCreated","summary":"Producto creado","description":"Se creó un producto, desde una caja o por la API. **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"product.created"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Product"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"product.updated":{"post":{"operationId":"webhookProductUpdated","summary":"Producto actualizado","description":"Se editó un producto, o una de sus variantes se editó o se eliminó por la API (`data.object` es el producto completo, ya sin la variante eliminada). Puede repetirse: trátalo como «vuelve a leer este objeto».\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"product.updated"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Product"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"customer.created":{"post":{"operationId":"webhookCustomerCreated","summary":"Cliente creado","description":"Se creó un cliente, desde una caja o por la API. **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"customer.created"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Customer"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"customer.updated":{"post":{"operationId":"webhookCustomerUpdated","summary":"Cliente actualizado","description":"Se editó un cliente, desde una caja o por la API. Puede repetirse: trátalo como «vuelve a leer este objeto».\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"customer.updated"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Customer"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"inventory.movement.created":{"post":{"operationId":"webhookInventoryMovementCreated","summary":"Movimiento de inventario registrado","description":"Se registró un movimiento de inventario, desde una caja o por la API. **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"inventory.movement.created"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/StockMovement"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"invoice.issued":{"post":{"operationId":"webhookInvoiceIssued","summary":"Factura electrónica emitida","description":"Un documento de la venta quedó emitido. **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"invoice.issued"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Invoice"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"invoice.rejected":{"post":{"operationId":"webhookInvoiceRejected","summary":"Factura electrónica rechazada","description":"La DIAN rechazó un documento de la venta. **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"invoice.rejected"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/Invoice"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"cash_session.closed":{"post":{"operationId":"webhookCashSessionClosed","summary":"Caja cerrada","description":"Se cerró un turno de caja. **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"cash_session.closed"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/CashSession"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"inventory.count.created":{"post":{"operationId":"webhookInventoryCountCreated","summary":"Conteo de inventario registrado","description":"Se registró un conteo físico de inventario (revisa su `status`). **Una sola vez por objeto.**\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"inventory.count.created"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/StockCount"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"inventory.stock.negative":{"post":{"operationId":"webhookInventoryStockNegative","summary":"Stock negativo en una bodega","description":"Un nivel de stock con conteo quedó por debajo de cero. Una vez por alerta.\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"inventory.stock.negative"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/StockLevel"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"product.deleted":{"post":{"operationId":"webhookProductDeleted","summary":"Producto eliminado","description":"Se eliminó un producto (y con él sus variantes). Llega una sola vez por objeto, lo elimine una caja (al sincronizar) o la API. `data.object` solo trae `id`, `object`, `deleted: true` y `deleted_at`: el objeto ya no existe.\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"product.deleted"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/DeletedWebhookObject"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"category.deleted":{"post":{"operationId":"webhookCategoryDeleted","summary":"Categoría eliminada","description":"Se eliminó una categoría. Llega una sola vez por objeto, lo elimine una caja (al sincronizar) o la API. `data.object` solo trae `id`, `object`, `deleted: true` y `deleted_at`: el objeto ya no existe.\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"category.deleted"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/DeletedWebhookObject"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}},"customer.deleted":{"post":{"operationId":"webhookCustomerDeleted","summary":"Cliente eliminado","description":"Se eliminó un cliente. Llega una sola vez por objeto, lo elimine una caja (al sincronizar) o la API. `data.object` solo trae `id`, `object`, `deleted: true` y `deleted_at`: el objeto ya no existe.\n\nResponde cualquier 2xx en menos de 10 s para confirmar la entrega; si no, Posdata reintenta.","tags":["Webhooks"],"parameters":[{"name":"Posdata-Signature","in":"header","required":true,"description":"`t=<unix>,v1=<hmac>`: HMAC-SHA256 con el secreto `whsec_` del endpoint sobre `<t>.<cuerpo crudo>`. Verifícala antes de procesar y rechaza timestamps viejos. Durante una rotación puede traer dos `v1`.","schema":{"type":"string"}},{"name":"Posdata-Event-Id","in":"header","required":true,"description":"Id del evento (el mismo de `GET /events/{id}`). Úsalo para deduplicar reintentos.","schema":{"type":"string"}},{"name":"Posdata-Event-Type","in":"header","required":true,"description":"Tipo del evento.","schema":{"type":"string"}},{"name":"Posdata-Delivery-Id","in":"header","required":true,"description":"Id de este intento de entrega.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","api_version","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"const":"customer.deleted"},"created_at":{"type":"string","format":"date-time"},"api_version":{"const":"2026-09-28"},"data":{"type":"object","required":["object"],"properties":{"object":{"$ref":"#/components/schemas/DeletedWebhookObject"}}}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta (o ninguna en 10 s) se reintenta."}}}}}}