Desarrolladores · versión 1.0.0
API de integraciones de Punto
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.
Hay 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).
Dirección base de la API
export PUNTO_API="https://api.punto.la"
export PUNTO_KEY="<tu key de integración>"Antes de empezar
Para conectar tu sistema hacen falta tres cosas, y las prepara el comercio desde el panel de Punto:
- El complemento API de integraciones activo. Se contrata desde el panel, en Mi plan. Sin él, todas las llamadas responden
403conreason: addon_api_required. - 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. - Una key de integración. Ver Autenticación.
El identificador de la caja se ve en la dirección del navegador al abrirla en Configuración.
Autenticación
Cada llamada lleva la key en el encabezado Authorization:
Authorization: Bearer <tu key>
La 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.
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):
| Alcance | Para qué sirve |
|---|---|
read (Lectura) | Consultar datos del comercio: catálogo, reportes. Es el que usa el conector MCP. |
write (Lectura y configuración) | Lo usa Punto AI para configurar el comercio. No sirve para esta API. |
integration (Integración de ventas) | Esta API: registrar ventas y órdenes, y además leer el catálogo. |
Los alcances no se incluyen entre sí: una key write no registra ventas y una integration no configura nada.
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.
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.
Límites de uso
Cada key tiene dos límites, que se cuentan por key (no por comercio ni por IP):
- 60 llamadas por minuto.
- 5.000 llamadas por día.
Al 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.
Errores
Toda respuesta tiene la misma forma. Si salió bien:
{ "ok": true, "data": { ... } }
Si no:
{
"ok": false,
"error": {
"message": "El total del pedido no coincide con lo que suman sus líneas...",
"code": 422,
"details": { "reason": "total_mismatch", "declared": 19000, "computed": 22000 }
}
}
Programá 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:
| Status | Qué hacer |
|---|---|
401 | Falta la key o es inválida. |
403 | La key no puede hacer esto: complemento inactivo, alcance equivocado, usuario sin permiso o cuenta del comercio bloqueada. Reintentar no lo arregla. |
404 | El pedido consultado no existe en este comercio. |
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. |
422 | El pedido tiene un dato que corregir. Arreglalo y volvé a mandarlo. |
429 | Límite de uso. Esperá y reintentá. |
5xx | Falla del servidor. Reintentá con el MISMO orderId: es seguro (ver Idempotencia). |
Los reason de cada operación están en su sección.
Idempotencia
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.
- Si mandás el mismo
orderIdotra vez —porque se cortó la conexión y no viste la respuesta—, Punto devuelve lo que ya había registrado, conduplicated: truey status200. Un alta nueva responde201conduplicated: false. - Si llegan dos llamadas del mismo pedido a la vez, se registra una sola y las dos reciben el mismo resultado.
- El reintento devuelve lo registrado aunque el catálogo haya cambiado desde entonces: nunca te va a decir que un pedido ya facturado falló.
Ventas 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.
Precios, impuestos y totales
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):
- 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.
- Por encima de la lista, se acepta como precio modificado, igual que cuando el cajero cambia un precio a mano.
- Agregados (
addons): se nombran poroptionIdy cantidad; el recargo lo pone el catálogo. ElunitPricede la línea es el precio con los agregados incluidos. - Envíos y recargos van en
charges, como línea propia con su descripción. Nunca sumados al precio de un producto.
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.
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.
Factura electrónica y KuDE
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.
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.
einvoice | Qué significa |
|---|---|
status: null | La caja no emite factura electrónica. La venta está registrada igual. |
sifenVerdict: pending | Enviada, esperando validación. |
sifenVerdict: approved (issued: true) | Aprobada. cdc y documentNumber son los datos del documento. |
sifenVerdict: rejected | Rechazada; sifenReason dice por qué. La corrige el comercio desde el panel: no reenvíes el pedido, porque ya está registrado. |
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.
issued: true significa que el documento fue aprobado, no solo enviado: un documento puede haberse enviado y ser rechazado después.
Órdenes: del pedido a la factura
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.
Se factura de dos maneras:
- Desde la caja, como cualquier orden (por ejemplo, un delivery que se cobra al volver el repartidor). Consultando
GET /v1/integrations/ordersvas a ver la venta cuando se cobre. - Desde tu sistema, con
POST /v1/integrations/salesyfromOrderId: 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.
Una 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.
Sincronizar el catálogo
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.
El 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.
Ventas
Pedidos ya cobrados, que se registran como venta y se facturan en el acto.
Consultar una venta
/v1/integrations/salesDevuelve 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).
Parámetros
| Campo | Tipo | Descripción |
|---|---|---|
orderIdobligatorio | string | El identificador del pedido en tu sistema, el mismo que mandaste al registrarlo. |
Ejemplo
Estado fiscal
curl "$PUNTO_API/v1/integrations/sales?orderId=WEB-10245" \
-H "Authorization: Bearer $PUNTO_KEY"Respuesta (dentro de data)
| Campo | Tipo | Descripción |
|---|---|---|
orderId | string | |
uid | string | Identificador interno de la venta (ecom: + tu orderId). |
transactionId | string (uuid) | |
duplicated | boolean | Solo en el alta: true si el pedido ya estaba registrado. |
document | object | null | |
document.number | string | null | Número de comprobante con su prefijo, listo para mostrar. |
document.invoiceNo | integer | null | |
document.prefix | string | null | Establecimiento y punto de expedición. |
document.serie | string | null | |
document.timbrado | string | null | |
document.date | string | null | |
document.total | number | null | |
einvoice | object | Estado de la factura electrónica. Ver Factura electrónica y KuDE. |
einvoice.issued | boolean | true solo si fue aprobada. |
einvoice.status | string | null | Estado del envío. null: la caja no emite factura electrónica. Valores: pending, sending, issued, error, cancelled, skipped. |
einvoice.sifenVerdict | string | null | Valores: pending, approved, rejected. |
einvoice.sifenReason | string | null | Motivo del rechazo. |
einvoice.cdc | string | null | Código de control del documento. |
einvoice.documentNumber | string | null | |
einvoice.portalUrl | string (uri) | null | Link del portal donde el comprador descarga su KuDE. |
order | object | Solo con fromOrderId: la orden facturada, ya cerrada. |
order.orderId | string | Tu identificador del pedido. |
order.id | string (uuid) | Identificador de la orden en Punto. |
order.number | integer | null | Número de la orden en la sucursal (el que ve la cocina). |
order.status | string | sent: en cola; in_progress: preparándose; ready: lista; out_for_delivery: en camino; delivered: entregada; closed: facturada; cancelled: cancelada. Valores: open, sent, in_progress, ready, out_for_delivery, delivered, closed, cancelled. |
order.fulfillment | string | Valores: delivery, takeaway, dine_in. |
order.scheduledFor | string | null | |
order.createdAt | string | |
order.registerId | string (uuid) | null | |
order.customerId | string (uuid) | null | |
order.delivery | object | null | La dirección con la que se registró la orden. |
order.delivery.address | string | null | |
order.delivery.reference | string | null | |
order.delivery.lat | number | null | |
order.delivery.lng | number | null | |
order.total | number | Total de la orden según sus líneas. |
Códigos de respuesta
| 200 | La venta y su estado fiscal (sin duplicated). |
| 401 | Falta la key o es inválida. |
| 403 | 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. |
| 404 | No hay nada registrado con ese orderId en este comercio. |
| 422 | El pedido tiene un dato que corregir. Ver reason. |
| 429 | Límite de uso de la key (60 por minuto, 5.000 por día). Esperá un minuto. |
Registrar una venta
/v1/integrations/salesRegistra 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.
Con fromOrderId, factura una orden que entró antes por POST /v1/integrations/orders y la cierra.
Motivos 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.
Cuerpo de la petición
| Campo | Tipo | Descripción |
|---|---|---|
orderIdobligatorio | string | Identificador del pedido en tu sistema. Ver Idempotencia. Hasta 45 caracteres. |
registerIdobligatorio | string (uuid) | La caja de Punto contra la que se registra. |
itemsobligatorio | array<object> | Hasta 200 elementos. |
items[].itemId | string (uuid) | Identificador del artículo en Punto. |
items[].sku | string | Código del artículo, si no mandás itemId. Hasta 120 caracteres. |
items[].quantityobligatorio | number | |
items[].unitPriceobligatorio | number | Precio por unidad que cobró tu sistema, con los agregados incluidos. |
items[].note | string | Nota de la línea (llega a la cocina en una orden). Hasta 200 caracteres. |
items[].addons | array<object> | Agregados del artículo (opciones de sus grupos). El recargo lo pone el catálogo. Hasta 50 elementos. |
items[].addons[].optionIdobligatorio | string (uuid) | |
items[].addons[].quantity | integer | Por defecto: 1. |
charges | array<object> | Hasta 200 elementos. |
charges[].descriptionobligatorio | string | Hasta 120 caracteres. |
charges[].amountobligatorio | number | |
charges[].taxId | string (uuid) | Impuesto del cargo. Sin él, el impuesto predeterminado del comercio. |
totalobligatorio | number | Lo que cobraste al comprador. Se compara con lo que suman las líneas. |
payment | object | Obligatorio al contado; prohibido con credit: true. |
payment.methodobligatorio | string | 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. Hasta 120 caracteres. |
payment.reference | string | Referencia de la pasarela, para conciliar. Hasta 120 caracteres. |
customer | object | El comprador. Se busca por documento; si no existe, se crea (hace falta name o fiscalName). Sin comprador, la venta sale a consumidor final. |
customer.document | string | Documento del comprador (identificador fiscal o personal). |
customer.documentType | string | Si el documento es el fiscal o el personal. Sin él, Punto lo deduce. Valores: ruc, ci. |
customer.name | string | |
customer.fiscalName | string | Razón social para la factura. |
customer.email | string (email) | |
customer.phone | string | Con código de país, formato E.164 (por ejemplo +595981000111). |
note | string | Hasta 500 caracteres. |
credit | boolean | Venta a crédito: sin payment, con dueDate y un comprador con crédito habilitado en Punto. Por defecto: false. |
dueDate | string (date) | Vencimiento de una venta a crédito. |
issuedAt | string (date-time) | Momento de la venta. Sin él, el de la llamada. |
fromOrderId | string | 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. Hasta 45 caracteres. |
Ejemplo
Venta cobrada con envío
curl -X POST "$PUNTO_API/v1/integrations/sales" \
-H "Authorization: Bearer $PUNTO_KEY" \
-H "Content-Type: application/json" \
-d '{
"orderId": "WEB-10245",
"registerId": "81c541da-640e-4891-a1a0-b32841e64c75",
"items": [
{ "sku": "CAFE-250", "quantity": 2, "unitPrice": 45000 }
],
"charges": [
{ "description": "Envío a domicilio", "amount": 15000 }
],
"total": 105000,
"payment": { "method": "Tarjeta de crédito", "reference": "psp_7f3a91" },
"customer": { "document": "4567890", "name": "Ana Gómez", "email": "[email protected]" }
}'Facturar una orden
curl -X POST "$PUNTO_API/v1/integrations/sales" \
-H "Authorization: Bearer $PUNTO_KEY" \
-H "Content-Type: application/json" \
-d '{
"orderId": "WEB-10246",
"fromOrderId": "WEB-10246",
"registerId": "81c541da-640e-4891-a1a0-b32841e64c75",
"items": [
{ "sku": "CAFE-250", "quantity": 1, "unitPrice": 45000 }
],
"total": 45000,
"payment": { "method": "Transferencia" }
}'Respuesta (dentro de data)
| Campo | Tipo | Descripción |
|---|---|---|
orderId | string | |
uid | string | Identificador interno de la venta (ecom: + tu orderId). |
transactionId | string (uuid) | |
duplicated | boolean | Solo en el alta: true si el pedido ya estaba registrado. |
document | object | null | |
document.number | string | null | Número de comprobante con su prefijo, listo para mostrar. |
document.invoiceNo | integer | null | |
document.prefix | string | null | Establecimiento y punto de expedición. |
document.serie | string | null | |
document.timbrado | string | null | |
document.date | string | null | |
document.total | number | null | |
einvoice | object | Estado de la factura electrónica. Ver Factura electrónica y KuDE. |
einvoice.issued | boolean | true solo si fue aprobada. |
einvoice.status | string | null | Estado del envío. null: la caja no emite factura electrónica. Valores: pending, sending, issued, error, cancelled, skipped. |
einvoice.sifenVerdict | string | null | Valores: pending, approved, rejected. |
einvoice.sifenReason | string | null | Motivo del rechazo. |
einvoice.cdc | string | null | Código de control del documento. |
einvoice.documentNumber | string | null | |
einvoice.portalUrl | string (uri) | null | Link del portal donde el comprador descarga su KuDE. |
order | object | Solo con fromOrderId: la orden facturada, ya cerrada. |
order.orderId | string | Tu identificador del pedido. |
order.id | string (uuid) | Identificador de la orden en Punto. |
order.number | integer | null | Número de la orden en la sucursal (el que ve la cocina). |
order.status | string | sent: en cola; in_progress: preparándose; ready: lista; out_for_delivery: en camino; delivered: entregada; closed: facturada; cancelled: cancelada. Valores: open, sent, in_progress, ready, out_for_delivery, delivered, closed, cancelled. |
order.fulfillment | string | Valores: delivery, takeaway, dine_in. |
order.scheduledFor | string | null | |
order.createdAt | string | |
order.registerId | string (uuid) | null | |
order.customerId | string (uuid) | null | |
order.delivery | object | null | La dirección con la que se registró la orden. |
order.delivery.address | string | null | |
order.delivery.reference | string | null | |
order.delivery.lat | number | null | |
order.delivery.lng | number | null | |
order.total | number | Total de la orden según sus líneas. |
Códigos de respuesta
| 200 | El pedido ya estaba registrado (duplicated: true): es la venta original. |
| 201 | Venta registrada. |
| 401 | Falta la key o es inválida. |
| 403 | 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. |
| 409 | El estado del comercio impide registrarlo. No reintentes igual. |
| 422 | El pedido tiene un dato que corregir. Ver reason. |
| 429 | Límite de uso de la key (60 por minuto, 5.000 por día). Esperá un minuto. |
Órdenes
Pedidos para preparar y entregar, que se facturan después.
Consultar una orden
/v1/integrations/ordersEn 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.
Parámetros
| Campo | Tipo | Descripción |
|---|---|---|
orderIdobligatorio | string | El identificador del pedido en tu sistema, el mismo que mandaste al registrarlo. |
Ejemplo
Estado de la orden
curl "$PUNTO_API/v1/integrations/orders?orderId=WEB-10246" \
-H "Authorization: Bearer $PUNTO_KEY"Respuesta (dentro de data)
| Campo | Tipo | Descripción |
|---|---|---|
orderId | string | Tu identificador del pedido. |
id | string (uuid) | Identificador de la orden en Punto. |
number | integer | null | Número de la orden en la sucursal (el que ve la cocina). |
status | string | sent: en cola; in_progress: preparándose; ready: lista; out_for_delivery: en camino; delivered: entregada; closed: facturada; cancelled: cancelada. Valores: open, sent, in_progress, ready, out_for_delivery, delivered, closed, cancelled. |
fulfillment | string | Valores: delivery, takeaway, dine_in. |
scheduledFor | string | null | |
createdAt | string | |
registerId | string (uuid) | null | |
customerId | string (uuid) | null | |
delivery | object | null | La dirección con la que se registró la orden. |
delivery.address | string | null | |
delivery.reference | string | null | |
delivery.lat | number | null | |
delivery.lng | number | null | |
total | number | Total de la orden según sus líneas. |
duplicated | boolean | Solo en el alta: true si la orden ya estaba registrada. |
invoiced | boolean | Si ya tiene una venta. |
sale | object | null | La venta que la facturó, con su estado fiscal. |
sale.transactionId | string (uuid) | |
sale.uid | string | |
sale.document | object | null | |
sale.document.number | string | null | Número de comprobante con su prefijo, listo para mostrar. |
sale.document.invoiceNo | integer | null | |
sale.document.prefix | string | null | Establecimiento y punto de expedición. |
sale.document.serie | string | null | |
sale.document.timbrado | string | null | |
sale.document.date | string | null | |
sale.document.total | number | null | |
sale.einvoice | object | Estado de la factura electrónica. Ver Factura electrónica y KuDE. |
sale.einvoice.issued | boolean | true solo si fue aprobada. |
sale.einvoice.status | string | null | Estado del envío. null: la caja no emite factura electrónica. Valores: pending, sending, issued, error, cancelled, skipped. |
sale.einvoice.sifenVerdict | string | null | Valores: pending, approved, rejected. |
sale.einvoice.sifenReason | string | null | Motivo del rechazo. |
sale.einvoice.cdc | string | null | Código de control del documento. |
sale.einvoice.documentNumber | string | null | |
sale.einvoice.portalUrl | string (uri) | null | Link del portal donde el comprador descarga su KuDE. |
Códigos de respuesta
| 200 | La orden (sin duplicated). |
| 401 | Falta la key o es inválida. |
| 403 | 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. |
| 404 | No hay nada registrado con ese orderId en este comercio. |
| 422 | El pedido tiene un dato que corregir. Ver reason. |
| 429 | Límite de uso de la key (60 por minuto, 5.000 por día). Esperá un minuto. |
Registrar una orden
/v1/integrations/ordersRegistra 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.
Motivos 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.
Cuerpo de la petición
| Campo | Tipo | Descripción |
|---|---|---|
orderIdobligatorio | string | Identificador del pedido en tu sistema. Ver Idempotencia. Hasta 45 caracteres. |
registerIdobligatorio | string (uuid) | La caja de Punto; la orden queda en su sucursal. |
fulfillmentobligatorio | string | Cómo llega al comprador: se envía, lo retira o se consume en el local. Valores: delivery, takeaway, dine_in. |
itemsobligatorio | array<object> | Hasta 200 elementos. |
items[].itemId | string (uuid) | Identificador del artículo en Punto. |
items[].sku | string | Código del artículo, si no mandás itemId. Hasta 120 caracteres. |
items[].quantityobligatorio | number | |
items[].unitPriceobligatorio | number | Precio por unidad que cobró tu sistema, con los agregados incluidos. |
items[].note | string | Nota de la línea (llega a la cocina en una orden). Hasta 200 caracteres. |
items[].addons | array<object> | Agregados del artículo (opciones de sus grupos). El recargo lo pone el catálogo. Hasta 50 elementos. |
items[].addons[].optionIdobligatorio | string (uuid) | |
items[].addons[].quantity | integer | Por defecto: 1. |
charges | array<object> | Hasta 200 elementos. |
charges[].descriptionobligatorio | string | Hasta 120 caracteres. |
charges[].amountobligatorio | number | |
charges[].taxId | string (uuid) | Impuesto del cargo. Sin él, el impuesto predeterminado del comercio. |
totalobligatorio | number | Lo que el comprador aprobó. Se compara con lo que suman las líneas. |
customer | object | Obligatorio con fulfillment: delivery. |
customer.document | string | Documento del comprador (identificador fiscal o personal). |
customer.documentType | string | Si el documento es el fiscal o el personal. Sin él, Punto lo deduce. Valores: ruc, ci. |
customer.name | string | |
customer.fiscalName | string | Razón social para la factura. |
customer.email | string (email) | |
customer.phone | string | Con código de país, formato E.164 (por ejemplo +595981000111). |
delivery | object | Obligatorio con fulfillment: delivery. |
delivery.addressobligatorio | string | Hasta 250 caracteres. |
delivery.reference | string | Cómo encontrar el lugar. Hasta 250 caracteres. |
delivery.lat | number | Van juntas con lng, o ninguna. Entre -90 y 90. |
delivery.lng | number | Entre -180 y 180. |
delivery.name | string | Nombre de la dirección en la ficha del comprador (por ejemplo, Casa). Hasta 80 caracteres. |
delivery.city | string | Hasta 80 caracteres. |
scheduledFor | string | Para cuándo es: fecha (AAAA-MM-DD) o fecha y hora ISO 8601. Sin él, es para ahora. |
note | string | Hasta 500 caracteres. |
Ejemplo
Orden con envío
curl -X POST "$PUNTO_API/v1/integrations/orders" \
-H "Authorization: Bearer $PUNTO_KEY" \
-H "Content-Type: application/json" \
-d '{
"orderId": "WEB-10246",
"registerId": "81c541da-640e-4891-a1a0-b32841e64c75",
"fulfillment": "delivery",
"items": [
{
"sku": "HAMB-CLASICA",
"quantity": 1,
"unitPrice": 42000,
"note": "Sin cebolla",
"addons": [ { "optionId": "c1a2b3c4-d5e6-4f70-8a91-b2c3d4e5f604", "quantity": 1 } ]
}
],
"charges": [ { "description": "Envío a domicilio", "amount": 10000 } ],
"total": 52000,
"customer": { "document": "4567890", "name": "Ana Gómez", "phone": "+595981000111" },
"delivery": {
"address": "Av. España 1234",
"reference": "Portón negro",
"lat": -25.2867,
"lng": -57.647
}
}'Respuesta (dentro de data)
| Campo | Tipo | Descripción |
|---|---|---|
orderId | string | Tu identificador del pedido. |
id | string (uuid) | Identificador de la orden en Punto. |
number | integer | null | Número de la orden en la sucursal (el que ve la cocina). |
status | string | sent: en cola; in_progress: preparándose; ready: lista; out_for_delivery: en camino; delivered: entregada; closed: facturada; cancelled: cancelada. Valores: open, sent, in_progress, ready, out_for_delivery, delivered, closed, cancelled. |
fulfillment | string | Valores: delivery, takeaway, dine_in. |
scheduledFor | string | null | |
createdAt | string | |
registerId | string (uuid) | null | |
customerId | string (uuid) | null | |
delivery | object | null | La dirección con la que se registró la orden. |
delivery.address | string | null | |
delivery.reference | string | null | |
delivery.lat | number | null | |
delivery.lng | number | null | |
total | number | Total de la orden según sus líneas. |
duplicated | boolean | Solo en el alta: true si la orden ya estaba registrada. |
invoiced | boolean | Si ya tiene una venta. |
sale | object | null | La venta que la facturó, con su estado fiscal. |
sale.transactionId | string (uuid) | |
sale.uid | string | |
sale.document | object | null | |
sale.document.number | string | null | Número de comprobante con su prefijo, listo para mostrar. |
sale.document.invoiceNo | integer | null | |
sale.document.prefix | string | null | Establecimiento y punto de expedición. |
sale.document.serie | string | null | |
sale.document.timbrado | string | null | |
sale.document.date | string | null | |
sale.document.total | number | null | |
sale.einvoice | object | Estado de la factura electrónica. Ver Factura electrónica y KuDE. |
sale.einvoice.issued | boolean | true solo si fue aprobada. |
sale.einvoice.status | string | null | Estado del envío. null: la caja no emite factura electrónica. Valores: pending, sending, issued, error, cancelled, skipped. |
sale.einvoice.sifenVerdict | string | null | Valores: pending, approved, rejected. |
sale.einvoice.sifenReason | string | null | Motivo del rechazo. |
sale.einvoice.cdc | string | null | Código de control del documento. |
sale.einvoice.documentNumber | string | null | |
sale.einvoice.portalUrl | string (uri) | null | Link del portal donde el comprador descarga su KuDE. |
Códigos de respuesta
| 200 | La orden ya estaba registrada (duplicated: true). |
| 201 | Orden registrada y enviada a preparar. |
| 401 | Falta la key o es inválida. |
| 403 | 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. |
| 422 | El pedido tiene un dato que corregir. Ver reason. |
| 429 | Límite de uso de la key (60 por minuto, 5.000 por día). Esperá un minuto. |
Catálogo
Lectura del catálogo del comercio, para sincronizar tu tienda.
Listar el catálogo
/v1/itemsEl 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.
Cada 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).
Parámetros
| Campo | Tipo | Descripción |
|---|---|---|
after | string | Recorrido completo por páginas: vacío para la primera, después el next de la respuesta anterior. |
limit | integer | Artículos por página (máximo 200). |
q | string | Búsqueda por nombre o SKU. |
Ejemplo
Primera página
curl "$PUNTO_API/v1/items?after=&limit=200" \
-H "Authorization: Bearer $PUNTO_KEY"Respuesta (dentro de data)
| Campo | Tipo | Descripción |
|---|---|---|
items | array<object> | |
items[].itemId | string (uuid) | |
items[].itemName | string | |
items[].itemSKU | string | null | |
items[].itemPrice | number | Precio de lista del catálogo. |
items[].itemStatus | integer | 1 activo; otro valor, archivado. |
items[].itemCanSale | boolean | Si se puede vender. |
items[].taxId | string (uuid) | null | |
items[].addonGroups | array<any> | null | Grupos de agregados con sus opciones (optionId, recargo). |
limit | integer | |
next | string | null | Desde dónde pedir la próxima página; null si fue la última. |
total | integer | null | Cantidad total de artículos, solo en la primera página. |
Códigos de respuesta
| 200 | Una página del catálogo. |
| 401 | Falta la key o es inválida. |
| 403 | 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. |
| 429 | Límite de uso de la key (60 por minuto, 5.000 por día). Esperá un minuto. |

