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ó.

Print diagram

  1. Tu sistema de caja construye un arreglo commands con el diseño del ticket.
  2. Envías el request de creación del trabajo — la terminal responde 202 Accepted de forma inmediata.
  3. La impresión se ejecuta de forma asíncrona en el hardware.
  4. Conoce el resultado final (COMPLETED o FAILED) de dos formas:
    • Webhook (push): la terminal notifica a la webhookUrl que definiste en el request.
    • Polling (pull): consulta el estado activamente con GET /terminal/v1/print_job?print_job_id={id}.

La estructura del request y la respuesta es idéntica en ambos modos de conexión. Lo que varía es únicamente el base URL:

TopologíaBase URL
Red Local (LAN / Wi-Fi)http://{TERMINAL_IP}:6868/terminal/v1
Nube (Internet) — UAThttps://uat-cloudt.kushkipagos.com/terminal/v1/{terminalSerial}/sync
Nube (Internet) — Producciónhttps://cloudt.kushkipagos.com/terminal/v1/{terminalSerial}/sync

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:

Anatomia de un ticket

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. Consulta la referencia API para mayor información.

{
"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 línea de comandos:

  • Bash
  • Javascript
  • Python
curl -X POST http://TERMINAL_IP:6868/terminal/v1/print \
-H "Content-Type: application/json" \
-d @body.json
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
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": "PENDING"
}

Resultado del trabajo

Tienes dos mecanismos para conocer el resultado final de un trabajo de impresión. Puedes usar uno o ambos en paralelo.

Opción A — Webhook (push)

Si enviaste un webhookUrl al encolar el trabajo, la terminal ejecuta un POST hacia esa URL cuando el trabajo cambia a COMPLETED o FAILED.

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."
}

Consulta la referencia API para mayor información sobre este webhook.


Opción B — Polling (pull)

Úsalo cuando tu sistema no puede recibir conexiones entrantes desde la terminal, o como respaldo al webhook.

Red Local: GET /terminal/v1/print_job?print_job_id={id}
Nube: POST /terminal/v1/{terminalSerial}/sync/print/job_status?print_job_id={id}

Consulta cada 2–3 segundos. Detén el polling cuando status sea COMPLETED o FAILED.

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

Consulta la referencia API para mayor información sobre este endpoint.

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

Acepta cobros con Kushki One

Realiza cobros con Kushki One

Errores de impresora

Consulta el catálogo de errores