Impresión en terminal SmartPOS

La Print API te da control total sobre la impresora térmica integrada en las terminales Kushki ONE. Imprime cualquier contenido desde tu sistema de caja —antes, durante o después de una transacción, o sin relación con ninguna— sin instalar drivers, SDK ni configurar hardware de tu lado.

Requisitos

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

Kushki ONE Print API sequence 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 inmediato.
  3. La impresión se ejecuta de forma asíncrona en el hardware.
  4. Conoces el resultado final por webhook o consultando el estado.

Los payloads y los headers son idénticos en todas las topologías. Las rutas no: el base URL termina en la terminal, y cada ruta lleva su propio prefijo.

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

Autenticación

La impresión usa el mismo mecanismo que las operaciones de pago — hash + cifrado, el único que tiene Kushki ONE:

ElementoValor
AuthorizationBasic seguido del hash SHA-512. El prefijo Basic es obligatorio
timestampUnix timestamp en segundos, dentro de ±5 minutos de la hora del servidor
CuerpoEl sobre cifrado {"data": "<iv_hex>:<ciphertext_hex>"}

El array commands que se muestra en esta página es el texto plano que se cifra, no lo que viaja por la red. El flujo completo está en Autenticación y cifrado de requests.

Casos de uso

La API no se limita a comprobantes de pago. Cualquier contenido que tu negocio necesite entregar en papel se dispara desde tu sistema de caja.

Caso de usoDescripción
Comprobante de pagoVenta directa, captura de pre-autorización, devolución o anulación
Cupón de descuentoCódigo para la próxima compra del cliente
Código QRContraseña de Wi-Fi, enlace de fidelización, recibo digital, información de producto
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 reversoComprobante impreso de una cancelación o devolución
ReimpresiónVuelve a imprimir un ticket anterior con el mismo printJobId
Contenido libreTexto, 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 dentro del arreglo commands.

Anatomy of a receipt mapped to Print API commands

Estructura del request

CampoTipoRequeridoDescripción
commandsarreglo✅Lista ordenada de comandos de impresión
printJobIdtexto—Clave de idempotencia. Si lo omites, se genera un UUID
externalReferencetexto—Referencia libre de tu integración, por ejemplo Mesa-14
webhookUrltexto—URL que recibirá el resultado cuando el trabajo termine
skipIfBusybooleano—Con true, devuelve 409 de inmediato si la cola está ocupada. Por defecto false

Tipos de comandos

TipoDescripción
textLínea de texto con tamaño, alineación, negrita, cursiva y subrayado
columnsFila multicolumna con anchos proporcionales, ideal para producto y 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 o JPG en Base64. Usa algorithm: BINARIZATION para logotipos
qrGenera un código QR en el hardware de la impresora
barcodeGenera un código de barras CODE128 en el hardware

Ejemplo completo

Este request construye un recibo con logotipo, encabezado, ítems, total, código QR y corte automático.

{
"printJobId": "TICKET-190209",
"externalReference": "Mesa-14",
"webhookUrl": "https://api.tunegocio.com/webhook/print-events",
"skipIfBusy": false,
"commands": [
{ "type": "image", "base64Image": "iVBORw0KGgoAAAANSUhEUg...", "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": "columns", "columns": [
{ "text": "2x Combo Hamburguesa", "weight": 2, "align": "LEFT" },
{ "text": "30,000.00 COP", "weight": 1, "align": "RIGHT" } ] },
{ "type": "columns", "columns": [
{ "text": "1x Jugo Natural", "weight": 2, "align": "LEFT" },
{ "text": "8,000.00 COP", "weight": 1, "align": "RIGHT" } ] },
{ "type": "divider", "dividerType": "SOLID" },
{ "type": "columns", "columns": [
{ "text": "TOTAL", "weight": 2, "align": "LEFT" },
{ "text": "38,000.00 COP", "weight": 1, "align": "RIGHT" } ] },
{ "type": "qr", "content": "https://tunegocio.com/recibo/TICKET-190209", "dotSize": 6, "errorLevel": "M", "align": "CENTER" },
{ "type": "feed", "lines": 3 },
{ "type": "cut" }
]
}

Envía el request desde tu back-end:

  • Javascript
  • Python
const res = await fetch(`${BASE_URL}/print`, {
method: "POST",
headers: buildHeaders(payload), // Authorization + timestamp
body: JSON.stringify(payload),
});
const job = await res.json();
console.log(res.status, job.printJobId, job.status);
// 202 TICKET-190209 PENDING
import requests
res = requests.post(f"{BASE_URL}/print",
headers=build_headers(payload), json=payload)
job = res.json()
print(res.status_code, job["printJobId"], job["status"])
# 202 TICKET-190209 PENDING

La terminal responde de inmediato:

{
"printJobId": "TICKET-190209",
"status": "PENDING",
"message": "Impresión encolada correctamente"
}
CódigoSignificado
202 AcceptedTrabajo encolado. Devuelve el printJobId y estado PENDING
400 Bad RequestPayload mal formado o valor de enumerado desconocido
409 ConflictYa existe un trabajo en PENDING o IN_PROGRESS

Resultado del trabajo

Tienes dos mecanismos para conocer el resultado final. Puedes usar uno o ambos en paralelo.

Opción A: webhook

Si enviaste webhookUrl al encolar, la terminal hace 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."
}

Opción B: consulta el estado

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

Red Local

GET /terminal/v1/print_job?print_job_id=TICKET-190209

Nube

POST /terminal/v1/{terminalSerial}/sync/print_job
{
"print_job_id": "TICKET-190209"
}

Consulta cada 2 o 3 segundos y detén el sondeo cuando status sea COMPLETED o FAILED.

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

Estados del trabajo

statusDescripción
PENDINGEn cola, esperando turno
IN_PROGRESSEl driver está enviando comandos a la impresora
COMPLETEDTicket impreso y cortado correctamente
FAILEDError físico durante la impresión. Revisa errorCode

Códigos de error de hardware

Los valores posibles de errorCode son OUT_OF_PAPER, COVER_OPEN, COVER_INCOMPLETE, PAPER_JAM, PRINTER_HOT, MOTOR_HOT, CUTTER_ERROR, OFFLINE y UNKNOWN_ERROR. Llegan con type: TERMINAL-PRINTER en el cuerpo del error.

Una cola ocupada no es uno de ellos: llega como TER-004 con type: TERMINAL, y por HTTP como un 409.

Buenas prácticas

  • Envía un printJobId propio para poder reimprimir el mismo ticket y para descartar duplicados en tu sistema.
  • Usa externalReference para vincular el ticket con tu orden, mesa o factura.
  • Responde 2xx al webhook antes de procesarlo. Un endpoint lento hace que pierdas la notificación.
  • Trata FAILED como una condición operativa, no como un error de tu integración: muestra el errorMessage al operador para que resuelva el problema físico.
  • Envía las imágenes ya binarizadas y del ancho correcto. Un logotipo pesado alarga el tiempo de impresión.
Acepta cobros con Kushki ONE

Procesa cobros presenciales y combínalos con la impresión del comprobante.

Errores de impresora

Consulta la causa y la acción recomendada para cada código de error de hardware.