{"openapi":"3.1.0","info":{"title":"API de integraciones de Punto","version":"1.0.0","summary":"Registrá en Punto las ventas y los pedidos de tu tienda online.","description":"Con esta API, el sistema de tu comercio (una tienda online, un ERP, una app de pedidos) le manda a Punto cada pedido y Punto hace el resto: da de alta al comprador, descuenta stock, calcula los impuestos, numera el comprobante, emite la factura electrónica cuando corresponde y lo suma a los reportes, igual que si la venta se hubiera hecho en el mostrador.\n\nHay dos entradas: **ventas** (un pedido ya cobrado, que se factura en el acto) y **órdenes** (un pedido para preparar y entregar, que se factura después).","contact":{"name":"Punto"}},"servers":[{"url":"https://api.punto.la","description":"Producción"}],"x-guides":[{"id":"antes-de-empezar","title":"Antes de empezar","body":"Para conectar tu sistema hacen falta tres cosas, y las prepara el comercio desde el panel de Punto:\n\n1. **El complemento API de integraciones activo.** Se contrata desde el panel, en *Mi plan*. Sin él, todas las llamadas responden `403` con `reason: addon_api_required`.\n2. **Una caja para el canal.** Cada pedido nombra la caja de Punto contra la que se registra (`registerId`). Se crea como cualquier otra caja, en *Configuración › Sucursales*, y es la que decide todo lo fiscal: si tiene timbrado y punto de expedición cargados, las ventas salen con factura; si no, se registran sin emitir. Usá una caja dedicada, sin ningún dispositivo conectado: si en esa caja también vende una persona, los dos numeran comprobantes de la misma serie.\n3. **Una key de integración.** Ver *Autenticación*.\n\nEl identificador de la caja se ve en la dirección del navegador al abrirla en Configuración."},{"id":"autenticacion","title":"Autenticación","body":"Cada llamada lleva la key en el encabezado `Authorization`:\n\n```http\nAuthorization: Bearer <tu key>\n```\n\nLa key se emite en *Configuración › Keys de integración* → **Nueva key**, eligiendo en *Qué puede hacer* la opción **Integración de ventas**. Se muestra una sola vez: guardala en el servidor de tu sistema, nunca en el navegador ni en una app que se distribuye.\n\n**Alcance de una key.** Cada key se emite con un alcance fijo, que no se puede cambiar después (se emite una nueva y se revoca la anterior):\n\n| Alcance | Para qué sirve |\n|---|---|\n| `read` (Lectura) | Consultar datos del comercio: catálogo, reportes. Es el que usa el conector MCP. |\n| `write` (Lectura y configuración) | Lo usa Punto AI para configurar el comercio. **No** sirve para esta API. |\n| `integration` (Integración de ventas) | Esta API: registrar ventas y órdenes, y además leer el catálogo. |\n\nLos alcances no se incluyen entre sí: una key `write` no registra ventas y una `integration` no configura nada.\n\n**Una key no puede más que su dueño.** Hereda los permisos y las sucursales del usuario que la emitió: emitila con un usuario que tenga permiso para vender y acceso a la sucursal de la caja del canal.\n\n**Cortar el acceso.** Revocar la key en el panel la deja sin efecto en el acto, sin tocar lo que ya se registró. Si se da de baja el complemento, todas las keys dejan de responder solas."},{"id":"limites","title":"Límites de uso","body":"Cada key tiene dos límites, que se cuentan por key (no por comercio ni por IP):\n\n- **60 llamadas por minuto.**\n- **5.000 llamadas por día.**\n\nAl pasarte, la llamada responde `429` y no se procesa. Esperá un minuto antes de reintentar y espaciá los reintentos (por ejemplo, 1, 2, 4 y 8 segundos entre intentos). Para consultar el estado fiscal de un pedido no hace falta más de una consulta cada 30 segundos."},{"id":"errores","title":"Errores","body":"Toda respuesta tiene la misma forma. Si salió bien:\n\n```json\n{ \"ok\": true, \"data\": { ... } }\n```\n\nSi no:\n\n```json\n{\n  \"ok\": false,\n  \"error\": {\n    \"message\": \"El total del pedido no coincide con lo que suman sus líneas...\",\n    \"code\": 422,\n    \"details\": { \"reason\": \"total_mismatch\", \"declared\": 19000, \"computed\": 22000 }\n  }\n}\n```\n\nProgramá contra `error.details.reason`, no contra el texto: el texto es para la persona que lee el registro y puede cambiar. Qué significa cada status:\n\n| Status | Qué hacer |\n|---|---|\n| `401` | Falta la key o es inválida. |\n| `403` | La key no puede hacer esto: complemento inactivo, alcance equivocado, usuario sin permiso o cuenta del comercio bloqueada. Reintentar no lo arregla. |\n| `404` | El pedido consultado no existe en este comercio. |\n| `409` | El estado del comercio impide registrarlo (por ejemplo, se agotó la numeración de la caja). No reintentes igual: hace falta que alguien lo resuelva en Punto. |\n| `422` | El pedido tiene un dato que corregir. Arreglalo y volvé a mandarlo. |\n| `429` | Límite de uso. Esperá y reintentá. |\n| `5xx` | Falla del servidor. Reintentá con el MISMO `orderId`: es seguro (ver *Idempotencia*). |\n\nLos `reason` de cada operación están en su sección."},{"id":"idempotencia","title":"Idempotencia","body":"Cada pedido viaja con `orderId`: el identificador del pedido en **tu** sistema (letras, números, punto, guion y guion bajo, hasta 45 caracteres). Es lo que garantiza que un pedido no se registre dos veces.\n\n- Si mandás el mismo `orderId` otra vez —porque se cortó la conexión y no viste la respuesta—, Punto devuelve lo que ya había registrado, con `duplicated: true` y status `200`. Un alta nueva responde `201` con `duplicated: false`.\n- Si llegan dos llamadas del mismo pedido a la vez, se registra una sola y las dos reciben el mismo resultado.\n- El reintento devuelve lo registrado aunque el catálogo haya cambiado desde entonces: nunca te va a decir que un pedido ya facturado falló.\n\nVentas y órdenes tienen cada una su espacio de `orderId`: el mismo pedido puede entrar primero como orden y después como venta con el mismo identificador."},{"id":"precios","title":"Precios, impuestos y totales","body":"Cada línea nombra un artículo del catálogo de Punto (por `itemId` o por `sku`), la cantidad y el precio unitario que cobró tu sistema. Punto compara ese precio con el de su lista (la del cliente, la de la sucursal o la del catálogo, en ese orden):\n\n- **Por debajo de la lista**, la diferencia queda registrada como **descuento de la línea**. Así el margen y el reporte de productos siguen siendo reales.\n- **Por encima de la lista**, se acepta como precio modificado, igual que cuando el cajero cambia un precio a mano.\n- **Agregados** (`addons`): se nombran por `optionId` y cantidad; el recargo lo pone el catálogo. El `unitPrice` de la línea es el precio con los agregados incluidos.\n- **Envíos y recargos** van en `charges`, como línea propia con su descripción. Nunca sumados al precio de un producto.\n\n**Los impuestos los calcula Punto** con las mismas reglas que una venta del mostrador: tu sistema no manda IVA ni totales por tasa, y si los manda se ignoran. Tampoco manda el número de comprobante: la numeración es de Punto.\n\n**El total se compara.** Mandás en `total` lo que cobraste (o vas a cobrar) al comprador, y Punto lo compara con lo que suman las líneas. Si la diferencia es mayor al redondeo (una unidad de la moneda por línea), el pedido no se registra y responde `422` con `reason: total_mismatch`, `declared` y `computed`. Nunca se factura algo distinto de lo que vio el comprador."},{"id":"factura-electronica","title":"Factura electrónica y KuDE","body":"Si la caja del canal tiene facturación electrónica configurada, cada venta emite su documento electrónico. En Paraguay (SIFEN) el documento se envía a validar en segundo plano, así que la respuesta del alta todavía no trae el veredicto: se consulta después.\n\n**Cómo seguirlo.** Consultá `GET /v1/integrations/sales?orderId=<id>` (o el de la orden, si la facturaste desde una orden) hasta que `einvoice.sifenVerdict` deje de ser `pending`. Una consulta cada 30 segundos alcanza; la mayoría se resuelven en pocos minutos.\n\n| `einvoice` | Qué significa |\n|---|---|\n| `status: null` | La caja no emite factura electrónica. La venta está registrada igual. |\n| `sifenVerdict: pending` | Enviada, esperando validación. |\n| `sifenVerdict: approved` (`issued: true`) | Aprobada. `cdc` y `documentNumber` son los datos del documento. |\n| `sifenVerdict: rejected` | Rechazada; `sifenReason` dice por qué. La corrige el comercio desde el panel: no reenvíes el pedido, porque ya está registrado. |\n\n**Dónde recibe el comprador su factura.** El KuDE (la representación imprimible del documento) queda disponible en el portal de Punto: `einvoice.portalUrl` es el link que tu tienda le muestra al comprador, por ejemplo en la confirmación del pedido o en el email que le mandás. Esta API no devuelve el PDF.\n\n`issued: true` significa que el documento fue **aprobado**, no solo enviado: un documento puede haberse enviado y ser rechazado después."},{"id":"ordenes","title":"Órdenes: del pedido a la factura","body":"Una orden es un pedido para preparar y entregar: entra a la cola de la cocina y a la pantalla de pedidos del local como cualquier otra, con origen *tienda online*. No se factura al crearla.\n\nSe factura de dos maneras:\n\n1. **Desde la caja**, como cualquier orden (por ejemplo, un delivery que se cobra al volver el repartidor). Consultando `GET /v1/integrations/orders` vas a ver la venta cuando se cobre.\n2. **Desde tu sistema**, con `POST /v1/integrations/sales` y `fromOrderId`: Punto registra la venta, la vincula a la orden y la cierra, como hace la caja al cobrarla. La venta toma al comprador de la orden si no mandás otro.\n\nUna orden con `scheduledFor` en otro día no aparece en la cocina hasta ese día. Una orden con envío (`fulfillment: delivery`) necesita al comprador y la dirección: la dirección queda guardada en su ficha y la orden conserva una copia, así el pedido sigue diciendo a dónde fue aunque el cliente la cambie después."},{"id":"catalogo","title":"Sincronizar el catálogo","body":"Con la misma key podés leer el catálogo del comercio (`GET /v1/items`) para mantener tu tienda sincronizada: identificadores, SKU, precio de lista y agregados. Recorrelo por páginas con `after`.\n\nEl resto de las consultas de lectura del comercio (reportes, clientes, stock) existe y la usa el conector MCP, pero todavía no forma parte de este contrato público: puede cambiar sin aviso."}],"tags":[{"name":"Ventas","description":"Pedidos ya cobrados, que se registran como venta y se facturan en el acto."},{"name":"Órdenes","description":"Pedidos para preparar y entregar, que se facturan después."},{"name":"Catálogo","description":"Lectura del catálogo del comercio, para sincronizar tu tienda."}],"security":[{"apiKey":[]}],"paths":{"/v1/integrations/sales":{"post":{"tags":["Ventas"],"operationId":"registerSale","summary":"Registrar una venta","description":"Registra un pedido ya cobrado como venta: descuenta stock, calcula impuestos, numera el comprobante y, si la caja lo tiene configurado, emite la factura electrónica.\n\nCon `fromOrderId`, factura una orden que entró antes por `POST /v1/integrations/orders` y la cierra.\n\nMotivos de rechazo (`error.details.reason`): `register_unavailable`, `item_unavailable`, `addons_invalid`, `price_below_addons`, `total_mismatch`, `tax_unavailable`, `payment_method_unknown`, `payment_method_cash`, `credit_requires_customer`, `credit_not_enabled`, `order_not_found`, `order_outlet_mismatch` (422); `order_cancelled`, `order_already_invoiced`, `invoice_range_exhausted`, `invoice_number_taken` (409). Un timbrado vencido responde 422 con `details.code: invoice_auth_expired`.","x-code-samples":[{"lang":"curl","label":"Venta cobrada con envío","source":"curl -X POST \"$PUNTO_API/v1/integrations/sales\" \\\n  -H \"Authorization: Bearer $PUNTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"orderId\": \"WEB-10245\",\n    \"registerId\": \"81c541da-640e-4891-a1a0-b32841e64c75\",\n    \"items\": [\n      { \"sku\": \"CAFE-250\", \"quantity\": 2, \"unitPrice\": 45000 }\n    ],\n    \"charges\": [\n      { \"description\": \"Envío a domicilio\", \"amount\": 15000 }\n    ],\n    \"total\": 105000,\n    \"payment\": { \"method\": \"Tarjeta de crédito\", \"reference\": \"psp_7f3a91\" },\n    \"customer\": { \"document\": \"4567890\", \"name\": \"Ana Gómez\", \"email\": \"ana@example.com\" }\n  }'"},{"lang":"curl","label":"Facturar una orden","source":"curl -X POST \"$PUNTO_API/v1/integrations/sales\" \\\n  -H \"Authorization: Bearer $PUNTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"orderId\": \"WEB-10246\",\n    \"fromOrderId\": \"WEB-10246\",\n    \"registerId\": \"81c541da-640e-4891-a1a0-b32841e64c75\",\n    \"items\": [\n      { \"sku\": \"CAFE-250\", \"quantity\": 1, \"unitPrice\": 45000 }\n    ],\n    \"total\": 45000,\n    \"payment\": { \"method\": \"Transferencia\" }\n  }'"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaleRequest"}}}},"responses":{"200":{"description":"El pedido ya estaba registrado (`duplicated: true`): es la venta original.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaleEnvelope"}}}},"201":{"description":"Venta registrada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaleEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"get":{"tags":["Ventas"],"operationId":"getSale","summary":"Consultar una venta","description":"Devuelve la venta registrada para un pedido y el estado de su factura electrónica. Consultala hasta que `einvoice.sifenVerdict` deje de ser `pending` (ver *Factura electrónica y KuDE*).","x-code-samples":[{"lang":"curl","label":"Estado fiscal","source":"curl \"$PUNTO_API/v1/integrations/sales?orderId=WEB-10245\" \\\n  -H \"Authorization: Bearer $PUNTO_KEY\""}],"parameters":[{"$ref":"#/components/parameters/OrderIdQuery"}],"responses":{"200":{"description":"La venta y su estado fiscal (sin `duplicated`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaleEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/integrations/orders":{"post":{"tags":["Órdenes"],"operationId":"registerOrder","summary":"Registrar una orden","description":"Registra un pedido para preparar y entregar. Entra directo a la cocina y a la pantalla de pedidos del local, con origen *tienda online*. No se factura: se factura después desde la caja o con `POST /v1/integrations/sales` y `fromOrderId`.\n\nMotivos de rechazo (`error.details.reason`, todos 422): `register_unavailable`, `item_unavailable`, `addons_invalid`, `price_below_addons`, `total_mismatch`, `tax_unavailable`, `delivery_requires_customer`, `delivery_address_required`, `order_invalid`.","x-code-samples":[{"lang":"curl","label":"Orden con envío","source":"curl -X POST \"$PUNTO_API/v1/integrations/orders\" \\\n  -H \"Authorization: Bearer $PUNTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"orderId\": \"WEB-10246\",\n    \"registerId\": \"81c541da-640e-4891-a1a0-b32841e64c75\",\n    \"fulfillment\": \"delivery\",\n    \"items\": [\n      {\n        \"sku\": \"HAMB-CLASICA\",\n        \"quantity\": 1,\n        \"unitPrice\": 42000,\n        \"note\": \"Sin cebolla\",\n        \"addons\": [ { \"optionId\": \"c1a2b3c4-d5e6-4f70-8a91-b2c3d4e5f604\", \"quantity\": 1 } ]\n      }\n    ],\n    \"charges\": [ { \"description\": \"Envío a domicilio\", \"amount\": 10000 } ],\n    \"total\": 52000,\n    \"customer\": { \"document\": \"4567890\", \"name\": \"Ana Gómez\", \"phone\": \"+595981000111\" },\n    \"delivery\": {\n      \"address\": \"Av. España 1234\",\n      \"reference\": \"Portón negro\",\n      \"lat\": -25.2867,\n      \"lng\": -57.647\n    }\n  }'"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderRequest"}}}},"responses":{"200":{"description":"La orden ya estaba registrada (`duplicated: true`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderEnvelope"}}}},"201":{"description":"Orden registrada y enviada a preparar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"get":{"tags":["Órdenes"],"operationId":"getOrder","summary":"Consultar una orden","description":"En qué punto está la orden (`status`) y, si ya se facturó —por esta API o en la caja—, la venta con su estado fiscal en `sale`.","x-code-samples":[{"lang":"curl","label":"Estado de la orden","source":"curl \"$PUNTO_API/v1/integrations/orders?orderId=WEB-10246\" \\\n  -H \"Authorization: Bearer $PUNTO_KEY\""}],"parameters":[{"$ref":"#/components/parameters/OrderIdQuery"}],"responses":{"200":{"description":"La orden (sin `duplicated`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/items":{"get":{"tags":["Catálogo"],"operationId":"listItems","summary":"Listar el catálogo","description":"El catálogo del comercio, por páginas. Para recorrerlo entero, pedí la primera página con `after` vacío y seguí con el valor de `next` hasta que venga `null`.\n\nCada artículo trae más campos que los documentados acá; los que no figuran pueden cambiar sin aviso. Sirve con cualquier key (`read` o `integration`).","x-code-samples":[{"lang":"curl","label":"Primera página","source":"curl \"$PUNTO_API/v1/items?after=&limit=200\" \\\n  -H \"Authorization: Bearer $PUNTO_KEY\""}],"parameters":[{"name":"after","in":"query","required":false,"description":"Recorrido completo por páginas: vacío para la primera, después el `next` de la respuesta anterior.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Artículos por página (máximo 200).","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"q","in":"query","required":false,"description":"Búsqueda por nombre o SKU.","schema":{"type":"string"}}],"responses":{"200":{"description":"Una página del catálogo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemsEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"Key de integración emitida en Configuración › Keys de integración."}},"parameters":{"OrderIdQuery":{"name":"orderId","in":"query","required":true,"description":"El identificador del pedido en tu sistema, el mismo que mandaste al registrarlo.","schema":{"type":"string","maxLength":45,"pattern":"^[A-Za-z0-9._\\-]+$"}}},"responses":{"Unauthorized":{"description":"Falta la key o es inválida.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Forbidden":{"description":"La key no puede hacer esto. `reason`: `addon_api_required` (complemento inactivo), `api_key_scope_missing` (alcance equivocado), `account_blocked`, `account_suspended`, `account_inactive` (cuenta del comercio). Un usuario sin permiso para vender responde 403 sin `reason`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"NotFound":{"description":"No hay nada registrado con ese `orderId` en este comercio.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Conflict":{"description":"El estado del comercio impide registrarlo. No reintentes igual.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Unprocessable":{"description":"El pedido tiene un dato que corregir. Ver `reason`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"TooManyRequests":{"description":"Límite de uso de la key (60 por minuto, 5.000 por día). Esperá un minuto.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"schemas":{"ErrorEnvelope":{"type":"object","required":["ok","error"],"properties":{"ok":{"type":"boolean","const":false},"error":{"type":"object","required":["message","code"],"properties":{"message":{"type":"string","description":"Texto para la persona que lee el registro. Puede cambiar."},"code":{"type":"integer","description":"El mismo status HTTP."},"details":{"type":"object","description":"Datos para programar. `reason` identifica el motivo.","properties":{"reason":{"type":"string","examples":["total_mismatch"]},"line":{"type":"integer","description":"Número de línea (desde 1) cuando el problema es de un artículo."},"declared":{"type":"number","description":"Con `total_mismatch`: el total que mandaste."},"computed":{"type":"number","description":"Con `total_mismatch`: lo que suman las líneas."}},"additionalProperties":true}}}}},"ItemLine":{"type":"object","description":"Un artículo del pedido. `itemId` o `sku`, al menos uno.","required":["quantity","unitPrice"],"properties":{"itemId":{"type":"string","format":"uuid","description":"Identificador del artículo en Punto."},"sku":{"type":"string","maxLength":120,"description":"Código del artículo, si no mandás `itemId`."},"quantity":{"type":"number","exclusiveMinimum":0},"unitPrice":{"type":"number","minimum":0,"description":"Precio por unidad que cobró tu sistema, con los agregados incluidos."},"note":{"type":"string","maxLength":200,"description":"Nota de la línea (llega a la cocina en una orden)."},"addons":{"type":"array","maxItems":50,"description":"Agregados del artículo (opciones de sus grupos). El recargo lo pone el catálogo.","items":{"$ref":"#/components/schemas/Addon"}}}},"Addon":{"type":"object","required":["optionId"],"properties":{"optionId":{"type":"string","format":"uuid"},"quantity":{"type":"integer","minimum":1,"default":1}}},"Charge":{"type":"object","description":"Envío, recargo o embalaje: una línea propia.","required":["description","amount"],"properties":{"description":{"type":"string","maxLength":120,"examples":["Envío a domicilio"]},"amount":{"type":"number","exclusiveMinimum":0},"taxId":{"type":"string","format":"uuid","description":"Impuesto del cargo. Sin él, el impuesto predeterminado del comercio."}}},"Customer":{"type":"object","description":"El comprador. Se busca por documento; si no existe, se crea (hace falta `name` o `fiscalName`). Sin comprador, la venta sale a consumidor final.","properties":{"document":{"type":"string","description":"Documento del comprador (identificador fiscal o personal)."},"documentType":{"type":"string","enum":["ruc","ci"],"description":"Si el documento es el fiscal o el personal. Sin él, Punto lo deduce."},"name":{"type":"string"},"fiscalName":{"type":"string","description":"Razón social para la factura."},"email":{"type":"string","format":"email"},"phone":{"type":"string","description":"Con código de país, formato E.164 (por ejemplo `+595981000111`)."}}},"Payment":{"type":"object","required":["method"],"properties":{"method":{"type":"string","maxLength":120,"description":"Medio de pago configurado en Punto: su identificador, código o nombre. El efectivo se rechaza (`payment_method_cash`): esa plata no entró al cajón del comercio."},"reference":{"type":"string","maxLength":120,"description":"Referencia de la pasarela, para conciliar."}}},"SaleRequest":{"type":"object","required":["orderId","registerId","items","total"],"properties":{"orderId":{"type":"string","maxLength":45,"pattern":"^[A-Za-z0-9._\\-]+$","description":"Identificador del pedido en tu sistema. Ver *Idempotencia*."},"registerId":{"type":"string","format":"uuid","description":"La caja de Punto contra la que se registra."},"items":{"type":"array","minItems":1,"maxItems":200,"items":{"$ref":"#/components/schemas/ItemLine"}},"charges":{"type":"array","maxItems":200,"items":{"$ref":"#/components/schemas/Charge"}},"total":{"type":"number","exclusiveMinimum":0,"description":"Lo que cobraste al comprador. Se compara con lo que suman las líneas."},"payment":{"$ref":"#/components/schemas/Payment","description":"Obligatorio al contado; prohibido con `credit: true`."},"customer":{"$ref":"#/components/schemas/Customer"},"note":{"type":"string","maxLength":500},"credit":{"type":"boolean","default":false,"description":"Venta a crédito: sin `payment`, con `dueDate` y un comprador con crédito habilitado en Punto."},"dueDate":{"type":"string","format":"date","description":"Vencimiento de una venta a crédito."},"issuedAt":{"type":"string","format":"date-time","description":"Momento de la venta. Sin él, el de la llamada."},"fromOrderId":{"type":"string","maxLength":45,"pattern":"^[A-Za-z0-9._\\-]+$","description":"`orderId` de una orden registrada con `POST /v1/integrations/orders` que esta venta factura. La orden tiene que ser de la misma sucursal que la caja."}}},"SaleEnvelope":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Sale"}}},"Sale":{"type":"object","properties":{"orderId":{"type":"string"},"uid":{"type":"string","description":"Identificador interno de la venta (`ecom:` + tu `orderId`)."},"transactionId":{"type":"string","format":"uuid"},"duplicated":{"type":"boolean","description":"Solo en el alta: `true` si el pedido ya estaba registrado."},"document":{"$ref":"#/components/schemas/SaleDocument"},"einvoice":{"$ref":"#/components/schemas/EInvoice"},"order":{"$ref":"#/components/schemas/OrderSummary","description":"Solo con `fromOrderId`: la orden facturada, ya cerrada."}}},"SaleDocument":{"type":["object","null"],"properties":{"number":{"type":["string","null"],"description":"Número de comprobante con su prefijo, listo para mostrar."},"invoiceNo":{"type":["integer","null"]},"prefix":{"type":["string","null"],"description":"Establecimiento y punto de expedición."},"serie":{"type":["string","null"]},"timbrado":{"type":["string","null"]},"date":{"type":["string","null"]},"total":{"type":["number","null"]}}},"EInvoice":{"type":"object","description":"Estado de la factura electrónica. Ver *Factura electrónica y KuDE*.","properties":{"issued":{"type":"boolean","description":"`true` solo si fue aprobada."},"status":{"type":["string","null"],"enum":["pending","sending","issued","error","cancelled","skipped",null],"description":"Estado del envío. `null`: la caja no emite factura electrónica."},"sifenVerdict":{"type":["string","null"],"enum":["pending","approved","rejected",null]},"sifenReason":{"type":["string","null"],"description":"Motivo del rechazo."},"cdc":{"type":["string","null"],"description":"Código de control del documento."},"documentNumber":{"type":["string","null"]},"portalUrl":{"type":["string","null"],"format":"uri","description":"Link del portal donde el comprador descarga su KuDE."}}},"Delivery":{"type":"object","required":["address"],"properties":{"address":{"type":"string","maxLength":250},"reference":{"type":"string","maxLength":250,"description":"Cómo encontrar el lugar."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Van juntas con `lng`, o ninguna."},"lng":{"type":"number","minimum":-180,"maximum":180},"name":{"type":"string","maxLength":80,"description":"Nombre de la dirección en la ficha del comprador (por ejemplo, Casa)."},"city":{"type":"string","maxLength":80}}},"OrderRequest":{"type":"object","required":["orderId","registerId","fulfillment","items","total"],"properties":{"orderId":{"type":"string","maxLength":45,"pattern":"^[A-Za-z0-9._\\-]+$","description":"Identificador del pedido en tu sistema. Ver *Idempotencia*."},"registerId":{"type":"string","format":"uuid","description":"La caja de Punto; la orden queda en su sucursal."},"fulfillment":{"type":"string","enum":["delivery","takeaway","dine_in"],"description":"Cómo llega al comprador: se envía, lo retira o se consume en el local."},"items":{"type":"array","minItems":1,"maxItems":200,"items":{"$ref":"#/components/schemas/ItemLine"}},"charges":{"type":"array","maxItems":200,"items":{"$ref":"#/components/schemas/Charge"}},"total":{"type":"number","exclusiveMinimum":0,"description":"Lo que el comprador aprobó. Se compara con lo que suman las líneas."},"customer":{"$ref":"#/components/schemas/Customer","description":"Obligatorio con `fulfillment: delivery`."},"delivery":{"$ref":"#/components/schemas/Delivery","description":"Obligatorio con `fulfillment: delivery`."},"scheduledFor":{"type":"string","description":"Para cuándo es: fecha (`AAAA-MM-DD`) o fecha y hora ISO 8601. Sin él, es para ahora."},"note":{"type":"string","maxLength":500}}},"OrderEnvelope":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Order"}}},"OrderSummary":{"type":"object","properties":{"orderId":{"type":"string","description":"Tu identificador del pedido."},"id":{"type":"string","format":"uuid","description":"Identificador de la orden en Punto."},"number":{"type":["integer","null"],"description":"Número de la orden en la sucursal (el que ve la cocina)."},"status":{"type":"string","enum":["open","sent","in_progress","ready","out_for_delivery","delivered","closed","cancelled"],"description":"`sent`: en cola; `in_progress`: preparándose; `ready`: lista; `out_for_delivery`: en camino; `delivered`: entregada; `closed`: facturada; `cancelled`: cancelada."},"fulfillment":{"type":"string","enum":["delivery","takeaway","dine_in"]},"scheduledFor":{"type":["string","null"]},"createdAt":{"type":"string"},"registerId":{"type":["string","null"],"format":"uuid"},"customerId":{"type":["string","null"],"format":"uuid"},"delivery":{"type":["object","null"],"description":"La dirección con la que se registró la orden.","properties":{"address":{"type":["string","null"]},"reference":{"type":["string","null"]},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]}}},"total":{"type":"number","description":"Total de la orden según sus líneas."}}},"Order":{"allOf":[{"$ref":"#/components/schemas/OrderSummary"},{"type":"object","properties":{"duplicated":{"type":"boolean","description":"Solo en el alta: `true` si la orden ya estaba registrada."},"invoiced":{"type":"boolean","description":"Si ya tiene una venta."},"sale":{"type":["object","null"],"description":"La venta que la facturó, con su estado fiscal.","properties":{"transactionId":{"type":"string","format":"uuid"},"uid":{"type":"string"},"document":{"$ref":"#/components/schemas/SaleDocument"},"einvoice":{"$ref":"#/components/schemas/EInvoice"}}}}}]},"ItemsEnvelope":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CatalogItem"}},"limit":{"type":"integer"},"next":{"type":["string","null"],"description":"Desde dónde pedir la próxima página; `null` si fue la última."},"total":{"type":["integer","null"],"description":"Cantidad total de artículos, solo en la primera página."}}}}},"CatalogItem":{"type":"object","description":"Un artículo del catálogo (solo los campos estables).","additionalProperties":true,"properties":{"itemId":{"type":"string","format":"uuid"},"itemName":{"type":"string"},"itemSKU":{"type":["string","null"]},"itemPrice":{"type":"number","description":"Precio de lista del catálogo."},"itemStatus":{"type":"integer","description":"1 activo; otro valor, archivado."},"itemCanSale":{"type":"boolean","description":"Si se puede vender."},"taxId":{"type":["string","null"],"format":"uuid"},"addonGroups":{"type":["array","null"],"description":"Grupos de agregados con sus opciones (`optionId`, recargo)."}}}}}}