Impresión en terminal SmartPOS

Impresión en terminal SmartPOS

La Print API te da control total sobre la impresora térmica integrada en los terminales Kushki ONE (Sunmi P3, Sunmi P2 SE). Puedes imprimir cualquier contenido desde tu sistema de caja — antes, durante o después de una transacción, o completamente independiente de una — sin necesidad de drivers, SDKs ni configuración de hardware en tu lado.

Cómo funciona

El ciclo de impresión tiene dos partes: un request síncrono que encola el trabajo, y una notificación asíncrona que te informa cuando terminó.

  1. Tu sistema de caja construye un arreglo commands con el diseño del ticket.
  2. Envías POST /terminal/v1/print — la terminal responde 202 Accepted de forma inmediata.
  3. La impresión se ejecuta de forma asíncrona en el hardware.
  4. El resultado final (COMPLETED o FAILED) se entrega via webhook a la URL que definiste en el request.

Casos de uso

La API no está limitada a comprobantes de pago. Cualquier contenido que tu negocio necesite entregar en papel puede dispararse desde tu sistema de caja:

Caso de usoDescripción
Comprobante de pagoCobro directo, captura de pre-autorización, devolución o anulación
Cupón de descuentoImprime un código de descuento para la próxima compra del cliente
Código QRContraseña de Wi-Fi, enlace a programa de fidelización, recibo digital, información de producto
Mensaje de agradecimientoMensaje de marca personalizado al final del recibo
Fidelización y promocionesSaldo de puntos, niveles de recompensa, ofertas especiales
Pre-cuenta o resumen de ordenTicket de cocina o resumen de mesa antes del cobro final
Constancia de reverso o anulaciónComprobante impreso de una cancelación o reembolso
ReimpresiónVuelve a imprimir cualquier ticket anterior usando el mismo printJobId
Contenido libreCualquier texto, imagen, QR o código de barras — sin necesidad de una transacción

Anatomía de un ticket

Cada sección visual del recibo corresponde a un tipo de comando en el arreglo commands. La siguiente imagen muestra cómo mapear el diseño del ticket a los comandos de la API:

Tipos de comandos

TipoDescripción
textLínea de texto con tamaño, alineación, negrita, cursiva y subrayado
columnsFila multi-columna con anchos proporcionales — ideal para producto + precio
dividerLínea separadora a todo el ancho (SOLID, DOTTED o EMPTY)
feedAvanza el papel N líneas en blanco
spaceInserta espacio vertical preciso en píxeles
cutActiva la cuchilla de corte (se ignora de forma segura en terminales sin cuchilla)
imageImprime una imagen PNG/JPG en Base64 — usa algorithm: BINARIZATION para logos
qrGenera un código QR directamente en el hardware de la impresora
barcodeGenera un código de barras CODE128 directamente en el hardware

Ejemplo completo

El siguiente ejemplo construye un recibo completo: logo de comercio, encabezado, items de la orden, total, QR y corte automático.

{
"printJobId": "TICKET-190209",
"externalReference": "Mesa-14",
"webhookUrl": "https://api.tunegocio/webhook/print-events",
"skipIfBusy": false,
"commands": [
{
"type": "image",
"base64Image": "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAK...",
"align": "CENTER",
"width": 300,
"algorithm": "BINARIZATION"
},
{
"type": "text",
"text": "RESTAURANTE EL BUEN SABOR\n",
"align": "CENTER",
"size": 32,
"bold": true
},
{
"type": "text",
"text": "NIT: 900.123.456-7\n",
"align": "CENTER",
"size": 22
},
{ "type": "divider", "dividerType": "DOTTED" },
{
"type": "text",
"text": "Fecha: 17/03/2024 14:32\n",
"align": "LEFT",
"size": 20
},
{ "type": "divider", "dividerType": "SOLID" },
{
"type": "columns",
"columns": [
{ "text": "2x Combo Hamburguesa", "weight": 2, "align": "LEFT" },
{ "text": "$30.000", "weight": 1, "align": "RIGHT" }
]
},
{
"type": "columns",
"columns": [
{ "text": "1x Jugo Natural", "weight": 2, "align": "LEFT" },
{ "text": "$8.000", "weight": 1, "align": "RIGHT" }
]
},
{ "type": "divider", "dividerType": "SOLID" },
{
"type": "columns",
"columns": [
{ "text": "TOTAL", "weight": 2, "align": "LEFT" },
{ "text": "$38.000", "weight": 1, "align": "RIGHT" }
]
},
{
"type": "qr",
"content": "https://tunegocio/recibo/TICKET-190209",
"dotSize": 6,
"errorLevel": "M",
"align": "CENTER"
},
{ "type": "feed", "lines": 3 },
{ "type": "cut" }
]
}

Envía el request desde tu backend o con cURL:

Reemplaza TERMINAL_IP con la IP estática o reserva DHCP asignada a tu terminal, y 6868 con el puerto configurado si usas uno distinto.

Envía el request desde tu backend o línea de comandos:

cURL

curl -X POST http://TERMINAL_IP:6868/terminal/v1/print \
-H "Content-Type: application/json" \
-d @body.json

JavaScript

const res = await fetch("http://TERMINAL_IP:6868/terminal/v1/print", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
console.log(res.status); // 202

Python

import requests
res = requests.post(
"http://TERMINAL_IP:6868/terminal/v1/print",
json=payload
)
print(res.status_code) # 202

La terminal responde de forma inmediata con 202 Accepted:

{
"printJobId": "TICKET-190209",
"status": "QUEUED"
}

Resultado del trabajo (Webhook)

Cuando la impresión finaliza, la terminal envía un POST a tu webhookUrl con el resultado:

Trabajo exitoso

{
"printJobId": "TICKET-190209",
"status": "COMPLETED",
"externalReference": "Mesa-14"
}

Fallo de hardware

{
"printJobId": "TICKET-190209",
"status": "FAILED",
"externalReference": "Mesa-14",
"errorCode": "OUT_OF_PAPER",
"errorMessage": "La impresora está sin papel."
}

Los posibles valores de errorCode son: OUT_OF_PAPER, COVER_OPEN, COVER_INCOMPLETE, PAPER_JAM, BUSY, PRINTER_HOT, MOTOR_HOT, CUTTER_ERROR, OFFLINE, UNKNOWN_ERROR.

Create Print Job

Documentación técnica completa del endpoint POST /terminal/v1/print: parámetros, esquemas, ejemplos de request/response y códigos de error.

Print Job Webhook

Estructura del payload asíncrono que recibirás en tu webhookUrl cuando el trabajo de impresión finalice.