1. Kushki One
Kushki Docs
Español
  • Español
  • English
  • Inicio
  • Inicio rápido
    • Últimas novedades
    • Preguntas frecuentes
    • Paso a producción
    • Política de cambios importantes del API
    • Datos de prueba
    • Códigos de error
  • Glosario de pagos
    • Glosario de pagos
  • Pagos únicos con tarjeta (Online)
    • Network Tokens
    • Marcas de tarjeta soportadas
    • Funcionalidades por modelo de negocio
    • Guía de integración Comisiones a terceros
    • ¿Cómo funcionan las Comisiones a terceros?
    • Pagos en un paso
      • Acepta un pago con tarjeta
      • Cargo directo (sin token)
      • ¿Cómo funcionan los pagos con tarjeta?
      • Acepta pagos únicos con OTP
      • Códigos de error autenticación OTP
      • Códigos de error pagos únicos con tarjeta
    • Pagos en dos pasos
      • Recibe pagos con autorización y captura
      • ¿Cómo funcionan los pagos únicos con autorización y captura?
    • Devoluciones
      • Devoluciones, anulaciones y reembolsos
    • Autenticación 3DS
      • Integración 3DS API + librería kushki.js
      • Introducción a 3DS
      • Integración 100% API de 3DS
      • Integración 3DS con librería kushki.js
      • Códigos de error autenticación 3DS
    • Pagos con Apple Pay
      • Configuración de Apple Pay
      • Pruebas en Sandbox Apple Pay
  • Pagos recurrentes con tarjeta (Online)
    • Autentica tus suscripciones con 3DS
    • Apple Pay en Suscripciones
    • Suscripciones externas a Kushki
    • Acepta pagos one click con 3DS
    • Funcionalidades por modelo de negocio
    • Códigos de error en cargos recurrentes
    • Pagos calendarizados
      • ¿Cómo funcionan los cargos recurrentes con tarjeta?
      • Maneja tus cargos calendarizados
      • Crea un cargo recurrente
    • Pagos OneClick
      • Genera pagos one click
      • Recibe pagos OneClick con autorización y captura
      • ¿Cómo funcionan los pagos OneClick con autorización y captura?
  • Pagos con tarjeta presente
    • Acepta pagos con tarjeta presente
    • Datos de prueba
    • Webhooks para tarjeta presente
    • Cloud Terminal API
      • Acepta pagos
      • Anula una solicitud de pago
      • Consulta el estado de una petición de cobro
      • ¿Cómo imprimir un ticket personalizado?
    • App-to-app
      • Acepta pagos
    • Transacciones
      • Anula un pago
      • Transacciones
    • Terminal SDK
      • Acepta pagos
    • Kushki One
      • Autenticación y Cifrado de Requests
      • Realiza cobros con Kushki One
      • Formato de montos en Kushki ONE
      • Impresión en terminal SmartPOS
      • Catálogo Unificado de Errores — Kushki ONE Connect
      • Servicios asíncronos y webhooks
    • Raw card-present API
      • Acepta pagos
      • Script de ejemplo para cifrar información
      • Intercambio de claves criptográficas
      • Preguntas frecuentes
      • Códigos de error para transacciones con tarjeta presente
    • Kushki One App de Pagos
      • Devoluciones y PreAuth & Capture
      • Procesa un cobro
      • Pago Dividido en la terminal
      • Consulta tus transacciones
      • Configuración del terminal
  • Pagos con transferencias
    • Bancos y detalles de operación para pagos con transferencia bancaria
    • Recibe transferencias bancarias
    • Consulta el estado de una transacción
  • Dispersión de dinero
    • Transferencia bancaria
      • Dispersa a cuentas bancarias
      • Códigos de error para dispersiones por transferencia
  • Plugins
    • Shopify
      • Operación del Plugin
    • Vtex
      • Guía de integración VTEX
  • Links de pago
    • Smartlinks
  • Formularios y botones de pago
    • Kajita
      • Kajitas de pago
      • ¿Cómo funciona?
    • Botón de pago
      • ¿Cómo funciona el botón de pago?
      • Genera un botón de pago
  • Administración de sucursales
    • ¿Cómo realizar el onboarding de subcomercios vía API?
  • Notificaciones
    • Buenas prácticas
    • Consulta tus webhooks
    • Webhooks para pagos únicos
      • Webhook para pagos únicos con tarjeta
      • Webhook para pagos únicos con transferencia bancaria
      • Webhook para pagos únicos con efectivo
    • Webhooks para dispersiones
      • Webhook para dispersión de dinero con transferencia
    • Webhooks para botón de pagos
      • Webhooks con Botón de pago
    • Webhooks para smartlinks
      • Webhooks con Smartlinks
    • Webhooks para pagos recurrentes
      • Webhook para pagos recurrentes con tarjeta
    • Webhooks para devoluciones
      • Webhook para devoluciones
      • Webhook para contracargos
HomeMexico 🇲🇽
Ecuador 🇪🇨Chile 🇨🇱Colombia 🇨🇴Peru 🇵🇪
HomeMexico 🇲🇽
Ecuador 🇪🇨Chile 🇨🇱Colombia 🇨🇴Peru 🇵🇪
Status
Soporte / Support
Español
  • Español
  • English
  1. Kushki One

Servicios asíncronos y webhooks

Inicia cobros sin bloquear tu sistema de caja y recibe el ciclo de vida completo de la transacción por webhook, evento por evento
🚧 Early Release — Beta
Este producto está en acceso temprano. Los parámetros, estructuras de respuesta y comportamientos pueden cambiar sin previo aviso. No uses esta versión en producción sin coordinarlo previamente con el equipo de integraciones de Kushki.
Un cobro con tarjeta presente depende de una persona: alguien tiene que acercar la tarjeta, elegir cuotas, digitar su PIN. Ese tiempo supera con frecuencia los 15 segundos que tolera la mayoría de las arquitecturas de caja.
Los servicios asíncronos resuelven ese problema. Tu sistema envía la intención de cobro, recibe un acuse inmediato y se libera. Kushki ONE Connect te notifica cada cambio de estado por webhook, hasta la respuesta final del adquirente.

Requisitos#

Antes de empezar
Un endpoint HTTPS público que reciba POST y responda con cualquier 2xx.
La ruta asíncrona configurada en tu integración: prefijo /async/ en lugar de /sync/.
Tu consumidor de webhooks preparado para recibir eventos repetidos. Explicamos por qué en Construye tu consumidor.

Cómo funciona#

1. POST /async/charge            →  respondemos TERMINAL_ACKNOWLEDGED de inmediato
2. POST a tu events_webhook_url  →  TERMINAL_ACKNOWLEDGED (primer evento, 1 a 2 s después)
3. La terminal opera la tarjeta  →  CARD_PRESENTED, APPROVAL_REQUESTED
4. Último evento                 →  APPROVAL, DECLINED, TERMINAL_REJECTED o TERMINAL_CANCELED,
                                    con el detalle de la operación
El acuse no es el resultado
La respuesta de una llamada asíncrona confirma únicamente que la terminal recibió la intención de cobro. No indica si la transacción fue aprobada. Para conocer el resultado debes consumir el webhook.

Activa los eventos#

Envía events_webhook_url en el cuerpo del request de cualquier operación asíncrona.
{
  "events_webhook_url": "https://api.tunegocio.com/webhook/terminal-events",
  "amount": {
    "iva": 0,
    "subtotal_iva": 0,
    "subtotal_iva0": 12100,
    "extra_taxes": { "airport_tax": 0, "iac": 0, "ice": 0, "travel_agency": 0 }
  },
  "client_transaction_id": "82517631-2789-4efb-8018-6234f35be2b6",
  "metadata": {
    "reference": "ABC12345",
    "customer_email": "cliente@ejemplo.com",
    "device": "SUNMI-T2"
  }
}
Solo en modo asíncrono
events_webhook_url se acepta únicamente en los endpoints /async/. Las operaciones síncronas devuelven el resultado directamente en la respuesta HTTP, así que no emiten eventos.
Si omites el parámetro en una llamada asíncrona, la transacción se ejecuta igual, pero no recibes notificaciones ni el resultado final.

La respuesta y los eventos no tienen la misma forma#

Recibes dos tipos de mensaje, y conviene deserializarlos por separado:
La respuesta HTTP a tu llamada asíncrona. Siempre con status: TERMINAL_ACKNOWLEDGED y previous_status vacío. Incluye operation como eco de tu request y un objeto terminal en camelCase.
Cada entrega de webhook. Empieza con un TERMINAL_ACKNOWLEDGED propio (con event_id distinto al de la respuesta), sigue con los cambios de estado y termina con el resultado del adquirente. Aquí terminal viene en snake_case, y operation y raw_response solo llegan en el evento final.
Respuesta HTTP a un POST /async/charge:
{
  "event_id": "9cc0ee68-6454-4288-a8fc-4514abe6c453",
  "previous_status": "",
  "occurred_at": "2026-10-12T21:40:43.311Z",
  "status": "TERMINAL_ACKNOWLEDGED",
  "merchant_id": "20000000104598300000",
  "client_transaction_id": "82517631-2789-4efb-8018-6234f35be2b6",
  "terminal": {
    "serialNumber": "TJ54241P20911",
    "model": "P2SE-BPKT",
    "wifiMac": "",
    "room": "3.0.10",
    "terminal_id": "00000001"
  },
  "operation": {
    "type": "charge",
    "amount": {
      "iva": 0,
      "subtotal_iva": 0,
      "subtotal_iva0": 12100,
      "extra_taxes": { "airport_tax": 0, "iac": 0, "ice": 0, "travel_agency": 0 }
    },
    "client_transaction_id": "82517631-2789-4efb-8018-6234f35be2b6",
    "metadata": { "reference": "ABC12345", "customer_email": "cliente@ejemplo.com", "device": "SUNMI-T2" },
    "events_webhook_url": "https://api.tunegocio.com/webhook/terminal-events"
  }
}
En la respuesta, operation.type toma los valores charge, pre-auth, re-auth y capture. En reautorización y captura, operation incluye además el transaction_reference que enviaste.
Los errores que puede devolver la llamada (400, 401, 409, 422, 500) están en la referencia de API: Charge (Async) — Red Local · Charge (Async) — Nube.

Estados del ciclo de vida#

Kushki ONE modela el cobro como siete estados. Cinco los genera la terminal; solo APPROVAL y DECLINED provienen del adquirente.
statusOrigenQué significa
TERMINAL_ACKNOWLEDGEDTerminalLa terminal recibió la intención de cobro. Siempre es el primer estado
TERMINAL_CANCELEDTerminalEl tarjetahabiente canceló en la terminal, o tu caja envió un abort
CARD_PRESENTEDTerminalEl tarjetahabiente operó la tarjeta. reading_type indica cómo se leyó
TERMINAL_REJECTEDTerminalRechazo local antes de llegar al adquirente: tiempo de espera agotado, máximo de reintentos o validación. failure_reason indica la causa
APPROVAL_REQUESTEDTerminalLa transacción se envió al adquirente para su autorización
DECLINEDAdquirenteEl adquirente rechazó la transacción
APPROVALAdquirenteEl adquirente aprobó la transacción

Transiciones#

TERMINAL_ACKNOWLEDGED ─┬─→ CARD_PRESENTED ──┬─→ APPROVAL_REQUESTED ─┬─→ APPROVAL
                       │         │      ▲   │                       └─→ DECLINED
                       │         │      └───┘  tarjeta presentada de nuevo
                       │         └─→ TERMINAL_CANCELED
                       ├─→ TERMINAL_CANCELED
                       └─→ TERMINAL_REJECTED
APPROVAL_REQUESTED es el punto de no retorno
Cuando la transacción llega al adquirente ya no puedes cancelarla con abort: tienes que esperar el evento final. Si resulta aprobada, revierte con una anulación el mismo día o con una devolución después del corte.
Una tarjeta rechazada en la terminal puede presentarse otra vez y generar un nuevo CARD_PRESENTED. Por eso el ciclo es un grafo y no una línea recta: no asumas una cantidad fija de eventos por transacción.
DECLINED y TERMINAL_REJECTED son los dos estados finales de rechazo. Trátalos igual en tu consumidor y lee la causa en failure_reason.
El tiempo de espera de la terminal no es un valor fijo
La terminal rechaza la operación si el tarjetahabiente no presenta la tarjeta o no completa el PIN dentro de su tiempo de espera. Ese tiempo depende del modelo de terminal y de la configuración del adquirente, y Kushki aún no publica un valor general. No implementes un temporizador propio que compita con el de la terminal: espera el evento TERMINAL_REJECTED (con failure_reason) o TERMINAL_CANCELED, y si tu caja necesita abandonar antes, envía abort. Si pierdes la conexión durante la espera, concilia con el endpoint de consulta de transacciones.
En un cobro aprobado sin incidentes recibirás cuatro eventos. En las pruebas de certificación, el ciclo completo tomó entre 8 y 33 segundos, un rechazo 11 segundos y una cancelación en la terminal 2,5 segundos; la espera más larga es siempre la del tarjetahabiente, entre TERMINAL_ACKNOWLEDGED y CARD_PRESENTED.

Estructura del evento#

Un cobro aprobado con lectura contactless produce los cuatro primeros eventos. Los tres primeros son livianos; el final trae la operación y, si fue aprobado, la respuesta del adquirente. Las dos últimas pestañas muestran los eventos finales de un rechazo y de una cancelación.
1 · TERMINAL_ACKNOWLEDGED
2 · CARD_PRESENTED
3 · APPROVAL_REQUESTED
4 · APPROVAL
TERMINAL_REJECTED
TERMINAL_CANCELED
{
  "event_id": "e7fc8be2-8186-418f-9515-99a8f638ecea",
  "occurred_at": "2026-10-12T21:40:44.800Z",
  "status": "TERMINAL_ACKNOWLEDGED",
  "merchant_id": "20000000104598300000",
  "client_transaction_id": "82517631-2789-4efb-8018-6234f35be2b6",
  "terminal": { "serial_number": "TJ54241P20911", "brand": "SUNMI", "model": "P2SE-BPKT" }
}
CampoPresenciaDescripción
event_idSiempreIdentificador único del evento. Úsalo para descartar duplicados
occurred_atSiempreFecha y hora en UTC, formato ISO 8601 con milisegundos
statusSiempreEstado actual, uno de los siete anteriores
merchant_idSiempreIdentificador de comercio en Kushki
client_transaction_idSiempreEl que enviaste en el request. Úsalo para correlacionar
terminalSiempreserial_number, brand y model del dispositivo
previous_statusDesde el 2.º eventoEstado anterior. El primer evento no lo incluye
reading_typeDesde CARD_PRESENTEDCHIP, CONTACTLESS o MAGNETIC_STRIPE
operationEvento finalLa operación tal como la procesó la terminal: type (CHARGE, PREAUTH, REAUTHORIZATION, CAPTURE), amount, metadata, events_webhook_url y banderas de la operación. Llega en APPROVAL, TERMINAL_REJECTED y TERMINAL_CANCELED
operation.transaction_referenceEvento final, en reautorización y capturaLa referencia original que enviaste en el request (la del preauth)
failure_reasonTERMINAL_REJECTED y DECLINEDtype, code y message del rechazo. Interprétalo con el Catálogo de errores. TERMINAL_CANCELED no lo incluye
raw_responseSolo en APPROVALRespuesta del adquirente: transaction_reference, ticket_number, transaction_status, transaction_type, authorized_amount, kushki_response, franchise, card_type, card_data y campos ISO 8583 (F11, F38, F39, F55)
raw_response.transaction_referenceSolo en APPROVALLa referencia nueva de esta operación. Guárdala: es la que necesitas para capturar, reautorizar, anular o devolver
Dos referencias en el mismo evento
En una captura o reautorización, operation.transaction_reference repite la referencia del preauth que enviaste, y raw_response.transaction_reference trae la referencia nueva de la captura o reautorización. Para conciliar y anular usa siempre la de raw_response.
Los eventos usan snake_case
Todos los campos del evento, incluidos los de terminal, operation y raw_response, van en snake_case (serial_number, subtotal_iva0, events_webhook_url). La respuesta HTTP inmediata es la excepción: su objeto terminal usa camelCase (serialNumber, wifiMac). Deserializa cada mensaje tal como llega.
El evento no incluye el número de tarjeta
El webhook no transporta el PAN ni el nombre del tarjetahabiente. El evento final sí trae la franquicia, el tipo de tarjeta y, en raw_response.card_data, el banco emisor, la marca y el país de emisión.
No reconstruyas requests desde el evento
operation.amount del evento final no es una copia de tu request: omite iva y subtotal_iva cuando van en cero y agrega currency y tip. No reutilices un monto del evento para armar un nuevo request. Revisa Formato de montos en Kushki ONE.

Entrega y reintentos#

Tu endpoint debe confirmar la recepción con cualquier código 2xx. Cualquier otra respuesta se evalúa según esta política:
ResultadoComportamiento
2xxEntrega exitosa. No hay reintentos
Timeout, conexión cerrada o fallo de DNSReintenta
408, 429, 500, 502, 503, 504Reintenta
400, 401, 403, 404, 409, 422No reintenta: se considera un rechazo permanente
El reintento usa retroceso exponencial con variación aleatoria, sobre una base de 2 segundos:
espera = min(60s, base * 2^intento) + aleatorio(0..base)
La entrega se detiene tras 10 intentos o 15 minutos, según lo que ocurra primero.
Resiliencia sin conexión
Si la terminal pierde conectividad, encola los eventos de forma persistente y los reenvía cuando la red vuelve, preservando el orden por transacción. Una ráfaga de eventos atrasados después de una caída es comportamiento normal, no una falla.

Construye tu consumidor#

Como los eventos se reintentan y se reenvían desde la cola, tu endpoint debe ser idempotente.
1.
Descarta duplicados por event_id. Los reintentos y los reenvíos repiten el mismo identificador. Guarda los que ya procesaste.
2.
Correlaciona por client_transaction_id. Todos los eventos de una transacción lo comparten. El terminal.serial_number te dice qué dispositivo lo generó, pero no sirve como clave de correlación.
3.
Detecta huecos con previous_status. Si no coincide con el último estado que registraste para esa transacción, falta un evento o llegó fuera de orden. Concilia con el endpoint de consulta de transacciones (Nube o Red Local, según tu topología de integración).
4.
Responde rápido y procesa después. Devuelve 2xx de inmediato y encola el payload en tu sistema interno. Un endpoint lento provoca reintentos, y los reintentos te cuestan duplicados.
5.
Trata APPROVAL, DECLINED, TERMINAL_REJECTED y TERMINAL_CANCELED como finales. No llegan más eventos después. En APPROVAL, persiste raw_response.transaction_reference y raw_response.ticket_number; en los rechazos, registra failure_reason.
JavaScript
Python
Acepta cobros con Kushki ONE
Revisa todos los flujos de cobro disponibles y sus variantes síncronas.
Catálogo de errores
Interpreta el objeto failure_reason de los estados TERMINAL_REJECTED y DECLINED.
Modificado en 2026-10-21 16:29:15
Anterior
Catálogo Unificado de Errores — Kushki ONE Connect
Siguiente
Raw card-present API
Built with