Realiza cobros con Kushki One

La Payment API te permite procesar cobros presenciales con tarjeta desde tu sistema de caja hacia una terminal Kushki ONE en modo semi-integrado. La terminal gestiona toda la interacción con el tarjetahabiente y el chip EMV: tu sistema envía el monto y recibe el resultado.

Requisitos

Cómo funciona

Todos los endpoints comparten la misma estructura de request y respuesta, sin importar cómo conectes tu caja con la terminal. Lo único que cambia entre topologías es 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}
Nube (Internet) — Producciónhttps://cloudt.kushkipagos.com/terminal/v1/{terminalSerial}

Modos síncrono y asíncrono

Cada operación que requiere interacción con la terminal existe en dos variantes, bajo prefijos de ruta distintos.

ModoPrefijoComportamientoDónde llega el resultado
Síncrono/sync/Mantiene la conexión abierta hasta que el adquirente respondeEn la respuesta HTTP
Asíncrono/async/Responde de inmediato con un acuse TERMINAL_ACKNOWLEDGED. No bloqueaSolo por webhook

Operaciones disponibles

OperaciónRutaSíncronoAsíncronoQué hace
Venta/chargeCobro inmediato: autoriza y captura en un solo paso
Autorización/authorizationReserva fondos sin capturarlos
Captura/captureCobra los fondos de una autorización aprobada
Re-autorización/re_authorizationExtiende el monto o la vigencia de una autorización activa
Post propina/pos_tipAgrega propina a una transacción ya autorizada
Anulación/voidAnula una transacción el mismo día, antes del corte
Devolución/refundDevuelve fondos de una transacción ya liquidada
Cancelar/abortCancela una operación en curso en la terminal
Consulta en línea/transaction_search_onlineConsulta el historial en el adquirente
Consulta local/transaction_search_localConsulta el historial almacenado en la terminal

Conceptos clave

client_transaction_id

Identificador UUID v4 que genera tu sistema de caja. Funciona como clave de idempotencia: si la terminal ya procesó ese identificador, detecta el duplicado y evita el doble cobro.

Genera uno nuevo por cada venta. Reutilízalo solo cuando estés reintentando exactamente la misma operación tras un fallo de red.

transaction_reference

Identificador que genera Kushki y devuelve en la respuesta de cada transacción aprobada, dentro de rawResponse. Es el vínculo entre operaciones del mismo ciclo de vida.

Estructura del monto

El objeto amount se envía en unidades mínimas de la moneda, como número entero. La cantidad de decimales depende del país.

Campos opcionales de la venta

Estos campos aplican a /charge. La terminal gestiona los diálogos con el tarjetahabiente y ignora el campo cuando la funcionalidad no está habilitada en el DMS.

CampoTipoQué hace
amount.tipenteroAgrega propina al total
cashback_amountenteroRetiro de efectivo adicional a la compra. Envía 0 si no aplica
query_deferredbooleanoCon true, la terminal ofrece opciones de cuotas al tarjetahabiente

En /re_authorization dispones además de omit_card: con true, la operación se ejecuta sin pedir la tarjeta.

Flujos de pago

Venta directa

El flujo más común en retail. La terminal activa el lector al recibir el request y espera a que el tarjetahabiente complete la interacción.

POST /sync/charge → 200 OK (approved: true)

Pre-autorización y captura

Úsalo cuando el monto final no se conoce al momento de la interacción: hoteles, estaciones de servicio, restaurantes de cuenta abierta.

POST /sync/authorization → guarda transaction_reference
↓ (horas o días después)
POST /sync/capture → con el transaction_reference guardado

Puedes intercalar /re_authorization para ampliar el monto reservado o extender el plazo antes de capturar. Envía subtotal_iva0: 0 para extender solo la vigencia.

Vigencia de la autorización

Tipo de tarjetaVigencia desde la autorización
Débito (Visa / Mastercard)7 días
Crédito (Visa / Mastercard)28 días

La captura puede llegar hasta el 110% del total autorizado, sumando la autorización y todas las re-autorizaciones no canceladas. Se permite una sola captura por ciclo.

Propina posterior

Agrega una propina a una transacción ya autorizada. Úsalo cuando el tarjetahabiente decide el monto después del cobro inicial. Envía el valor en amount.tip junto al transaction_reference original.

Anulación y devolución

OperaciónCuándo la usas
Anulación (/void)El mismo día de la transacción, antes del horario de corte del procesador
Devolución (/refund)Cuando la transacción ya se liquidó, o si pasó el horario de corte

Autenticación

Incluye estos headers en cada request:

HeaderValor
AuthorizationFirma HMAC-SHA256 del cuerpo del request, codificada en Base64, usando tu Business-Code como llave
timestampUnix timestamp en milisegundos

Ejemplo de venta directa

Cobro de 120.00 COP sin desglose de impuestos.

  • Javascript
  • Python
const payload = {
amount: {
iva: 0, subtotal_iva: 0, subtotal_iva0: 12000,
extra_taxes: { airport_tax: 0, iac: 0, ice: 0, travel_agency: 0 },
},
client_transaction_id: crypto.randomUUID(),
};
const res = await fetch(`${BASE_URL}/sync/charge`, {
method: "POST",
headers: buildHeaders(payload),
body: JSON.stringify(payload),
});
const data = await res.json();
console.log(data.approved, data.rawResponse.transaction_reference);
import uuid, requests
payload = {
"amount": {
"iva": 0, "subtotal_iva": 0, "subtotal_iva0": 12000,
"extra_taxes": {"airport_tax": 0, "iac": 0, "ice": 0, "travel_agency": 0},
},
"client_transaction_id": str(uuid.uuid4()),
}
res = requests.post(f"{BASE_URL}/sync/charge",
headers=build_headers(payload), json=payload)
data = res.json()
print(data["approved"], data["rawResponse"]["transaction_reference"])

Buenas prácticas

  • Genera un client_transaction_id único por venta y reutilízalo solo en reintentos de la misma operación.
  • Persiste el transaction_reference en cuanto recibas la respuesta de autorización o cobro.
  • Verifica que los campos de amount sumen el total esperado antes de enviar el request.
  • Registra el client_transaction_id y el código HTTP de cada operación para facilitar la conciliación y el soporte.
  • Usa /abort solo mientras una transacción está activa en la terminal. Llamarlo después de que completó devuelve 409 Conflict.
  • Firma exactamente los mismos bytes que envías: serializa una vez, firma esa cadena y envía esa misma cadena.
Servicios asíncronos y webhooks

Integra el modo asíncrono: estados del ciclo de vida, estructura de los eventos y política de reintentos de entrega.

Catálogo de errores

Consulta los modelos de error, códigos por categoría y acciones correctivas para todos los endpoints.