ZealDeveloper Hub Beta
EN ES
App-to-App Integration · Android

Zeal Communicator SDK

Intégrate en el flujo de pago de Zeal en terminales Android: descuentos, recompensas, recibos digitales y devoluciones, con el Communicator SDK tipado en Kotlin.

La API de terceros es un servicio que ofrece Zeal para dar soporte a una aplicación de pago autónoma en terminales Android durante el flujo de pago. Esta guía especifica cómo una aplicación de pago se integra con la aplicación autónoma de Zeal.

Cómo funciona. La API de terceros utiliza mensajes de broadcast de Android encaminados a través de receptores declarados en el manifiesto. No hay endpoints REST que llamar desde fuera del dispositivo.

Cada evento de tarjeta identifica la tarjeta por su huella de la tarjeta (Card Fingerprint, loyalty_token), un identificador único de tarjeta que tu app de pago genera al leerla. Lee Huella de la tarjeta antes de empezar.

Instalación

Paso 1 · Agrega el repositorio Maven

Agrega el siguiente repositorio Maven a dependencyResolutionManagement en settings.gradle:

dependencyResolutionManagement {
  repositories {
      maven {
          url = uri("https://maven.pkg.github.com/zeal-io/Zeal-POS-App-Communicator-SDK")
          credentials {
              username = "*USERNAME*"
              password = "*PASSWORD*"
          }
      }
  }
}

Paso 2 · Agrega la dependencia

dependencies {
  // ...
  implementation "com.zeal.zealmodule:zeal_communicator_sdk:1.2.28"
}

Paso 3 · Inicializa la app de Zeal

Llama a este método al principio del ciclo de vida de la app, o antes de iniciar el flujo de pago, para inicializar la app de Zeal con los datos de tu comercio:

FlowHandler()
  .setTerminalInfo(context, "serialNumber", "terminalId", "merchantId")

Configuración compartida

Todas las acciones siguientes usan el mismo preámbulo: importa el SDK, crea un FlowHandler y elige un contexto más el tipo de transacción.

import com.zeal.zeal_communicator_sdk.*

val flowHandler = FlowHandler()
val context: Context = this // reemplázalo por tu contexto real
val transactionType: TransactionTypes = TransactionTypes.Sale // o Void / Refund

Acciones de transacción disponibles

afterAmountEnteracción
Se activa antes de la detección de la tarjeta. La aplicación de terceros puede gestionar la transacción con métodos alternativos distintos de las tarjetas de crédito o débito.
afterCardDetectedacción
Se activa tras la lectura de la tarjeta y antes de su verificación. Proporciona el monto total, la moneda y los seis primeros dígitos del PAN; útil para descuentos o validaciones personalizadas.
eReceiptacción
Se activa después de que se aprueba la transacción y antes de imprimir el recibo. En FlowHandler usa digitalReceipt con DigitalReceiptRequest.
afterTransactionacción
Se activa después de procesar el recibo y antes de volver a la pantalla de espera. Úsala para encuestas, captura de números de teléfono o alta en programas de fidelización.
reverseacción
Se activa cuando hay que revertir una venta completada. Marca la transacción original como revertida y deshaz los puntos, recompensas o cupones asociados.
refundacción
Se activa cuando se realiza una devolución. Marca la transacción como devuelta y revierte los beneficios concedidos por la venta original; puede vincularse a una venta anterior o procesarse de forma independiente.

Tipos de transacción

El enum TransactionTypes define los tipos de transacción disponibles:

enum class TransactionTypes {
  Sale,
  Void,
  Refund,
  PreAuth,
  Completion
}

Valores de tran_status

Cada respuesta incluye un tran_status que describe el resultado del canje:

tran_status {
  FULLY_COVERED, // el descuento cubre el monto íntegro de la transacción
  NEW_AMOUNT,    // el descuento cubre parcialmente el monto; se devuelve el resto
  SAME_AMOUNT,   // no se produjo ningún canje
  ERROR,         // error en el lado de Zeal o del canje
  CANCEL         // se omitió o se decidió no canjear puntos
}

Modelo de respuesta base

Todas las clases de respuesta extienden BaseResponse:

package com.zeal.zeal_communicator_sdk.communicationResponses

open class BaseResponse(
  var third_party_request_type: String,
  var tran_status: String,
  var message: String
)

Los modelos de solicitud y respuesta de cada acción están documentados en la ruta de venta y en la sección Devolución y reversión más abajo: AfterCardDetectedRequest, DigitalReceiptRequest, RefundTransactionRequest, MarkAsReverseRequest y sus respuestas correspondientes.

Huella de la tarjeta

loyalty_token lleva la huella de la tarjeta (Card Fingerprint), también llamada identificador único de tarjeta (Unique Card Identifier). Es el valor que le indica a Zeal qué tarjeta se ha usado: tu app de pago lo envía con cada evento de tarjeta (afterCardDetected, digitalReceipt y refund), y Zeal reconoce por él a un cliente que vuelve.

Tu app de pago obtiene la huella de la tarjeta al leerla, dentro de su propio procesamiento seguro de tarjetas, de una de estas dos formas:

  • Hash con clave: un HMAC-SHA-256 del PAN completo, con una clave que guardas tú.
  • Consulta a una bóveda: una bóveda de tokenización (vault) que devuelve el mismo identificador cada vez que ve la misma tarjeta, de modo que la huella no se deriva del propio PAN.

El número de tarjeta (PAN) nunca se envía a Zeal. El BIN (cardBin) y los cuatro últimos dígitos (masked_pan) que también envías no se usan para identificarla.

La huella de la tarjeta debe cumplir tres requisitos:

1 · Establerequisito
La misma tarjeta física genera siempre la misma huella en todas las compras, terminales y comercios.
2 · Irreversiblerequisito
Nadie sin tu clave o tu bóveda puede recuperar el PAN a partir de ella. La clave o la bóveda se quedan contigo y nunca se comparten con Zeal.
3 · Fija durante la integraciónrequisito
Mantén la misma clave o bóveda durante toda la vida de la integración. Cambiarla cambia todas las huellas y deja huérfanas todas las tarjetas inscritas.

Si tu app de pago ya genera un hash estable por tarjeta para sus propios fines, como un hash del PAN que expone el SDK de tu terminal, puedes enviar ese valor como huella de la tarjeta, siempre que cumpla los tres requisitos.

Zeal no prescribe cómo generarla: prescribe estabilidad e irreversibilidad.

¿No puedes generar una huella de la tarjeta que cumpla estos requisitos? Ponte en contacto con Zeal antes de desarrollar la integración.

AfterCardDetected

Se activa tras la lectura de la tarjeta y antes de su verificación. Ejecuta este paso primero en la ruta de venta y continúa después con el Recibo digital.

Enviar una acción

Construye un AfterCardDetectedRequest, con la huella de la tarjeta en loyalty_token, y suscríbete en FlowHandler:

val request = AfterCardDetectedRequest(
  loyalty_token = "HhYDMww7aJgcdyJPU6QVWpFAZPNRhSzkqNpErHM3hikU", // huella de la tarjeta, nunca el PAN
  currency_code = "818",
  decimal_shift = "2",
  amount = "100.00",
  phone_number = "",
  masked_pan = "1111",
  cardBin = "411111",
  par = "V0010013000000000000000000001" // opcional
)

flowHandler.afterCardDetected(
  context,
  transactionType,
  request
).subscribe({ response ->
  // AfterCardDetectedResponse — revisa tran_status, amount, transaction_id
}) { throwable ->
  if (throwable is NotRegisteredFlowException) {
      // la aplicación de destino no ha registrado ninguna acción para este paso
  } else {
      // otra excepción
  }
}

Modelos de solicitud y respuesta

package com.zeal.zeal_communicator_sdk.communicationRequests

class AfterCardDetectedRequest(
  var loyalty_token: String, // huella de la tarjeta, nunca el número de tarjeta
  var currency_code: String,
  var decimal_shift: String, // opcional
  var amount: String, // en formato double
  var phone_number: String = "",
  var masked_pan: String = "", // últimos 4 dígitos del número de tarjeta
  var cardBin: String = "", // primeros 6 u 8 dígitos del número de tarjeta
  var par: String? = null // opcional — referencia de cuenta de pago EMV
)
package com.zeal.zeal_communicator_sdk.communicationResponses

class AfterCardDetectedResponse(
  tran_status: String, // FULLY_COVERED, NEW_AMOUNT, SAME_AMOUNT, ERROR, CANCEL
  var transaction_id: String? = null, // id de canje necesario para completar el canje al final
  third_party_request_type: String,
  var decimal_shift: String,
  var amount: String,
  var currency_code: String
) : BaseResponse(third_party_request_type, tran_status)

Recibo digital

Se activa después de que se aprueba la transacción y antes de imprimir el recibo. Llámalo después de AfterCardDetected en la ruta de venta. La acción en el cable es eReceipt; el método y los modelos del SDK usan digitalReceipt / DigitalReceipt*. Envía en loyalty_token la misma huella de la tarjeta que en AfterCardDetected.

Enviar una acción

val request = DigitalReceiptRequest(
  currency_code = "818",
  decimal_shift = "2",
  amount = "100.00",
  entry_mode = "CHIP",
  card_brand = "VISA",
  card_type = "CREDIT",
  customer_receipt_data = "...",
  merchant_receipt_data = "...",
  loyalty_token = "HhYDMww7aJgcdyJPU6QVWpFAZPNRhSzkqNpErHM3hikU", // huella de la tarjeta, nunca el PAN
  third_party_approval_code = "123456",
  third_party_tran_date = "20260422",
  third_party_tran_time = "143055",
  phone_number = "",
  par = "V0010013000000000000000000001" // opcional
)

flowHandler.digitalReceipt(
  context,
  transactionType,
  request
).subscribe({ response ->
  // DigitalReceiptResponse — payment_reference para llamadas posteriores a reverse
}) { throwable ->
  if (throwable is NotRegisteredFlowException) {
      // la aplicación de destino no ha registrado ninguna acción para este paso
  } else {
      // otra excepción
  }
}

Modelos de solicitud y respuesta

package com.zeal.zeal_communicator_sdk.communicationRequests

class DigitalReceiptRequest(
  var currency_code: String,
  var decimal_shift: String,
  var amount: String,
  var entry_mode: String,
  var card_brand: String,
  var card_type: String,
  var customer_receipt_data: String,
  var merchant_receipt_data: String,
  var loyalty_token: String, // huella de la tarjeta, nunca el número de tarjeta
  var third_party_approval_code: String,
  var third_party_tran_date: String,
  var third_party_tran_time: String,
  var phone_number: String = "",
  var par: String? = null // opcional — referencia de cuenta de pago EMV
)
package com.zeal.zeal_communicator_sdk.communicationResponses

class DigitalReceiptResponse(
  tran_status: String,
  third_party_request_type: String,
  var payment_reference: String? = null
) : BaseResponse(third_party_request_type, tran_status)

Devolución y reversión

La devolución y la reversión están separadas de la ruta de venta. Úsalas al deshacer beneficios de una venta completada, no como el siguiente paso tras el recibo digital.

Devolución

Se activa cuando se realiza una devolución. Marca la transacción como devuelta y revierte los beneficios de la venta original; vincula con un transaction_id opcional o procésala de forma independiente.

Enviar una acción

val request = RefundTransactionRequest(
  transaction_id = "sale-txn-id", // opcional — vincular a la venta original
  currency_code = "818",
  decimal_shift = "2",
  amount = "100.00",
  card_brand = "VISA",
  card_type = "CREDIT",
  loyalty_token = "HhYDMww7aJgcdyJPU6QVWpFAZPNRhSzkqNpErHM3hikU", // huella de la tarjeta, nunca el PAN
  masked_pan = "1111",
  card_expiration_date = "1230",
  auth_code = "123456",
  par = "V0010013000000000000000000001" // opcional
)

flowHandler.refund(
  context,
  TransactionTypes.Refund,
  request
).subscribe({ response ->
  // RefundTransactionResponse
}) { throwable ->
  if (throwable is NotRegisteredFlowException) {
      // la aplicación de destino no ha registrado ninguna acción para este paso
  } else {
      // otra excepción
  }
}

Modelos de solicitud y respuesta

package com.zeal.zeal_communicator_sdk.communicationRequests

class RefundTransactionRequest(
  val transaction_id: String? = null, // id de la venta original (opcional)
  val currency_code: String,
  val decimal_shift: String,
  val amount: String,
  val card_brand: String,
  val card_type: String,
  val loyalty_token: String, // huella de la tarjeta, nunca el número de tarjeta
  val masked_pan: String? = null,
  val card_expiration_date: String? = null,
  val auth_code: String? = null,
  val par: String? = null // opcional — referencia de cuenta de pago EMV
)
package com.zeal.zeal_communicator_sdk.communicationResponses

class RefundTransactionResponse(
  tran_status: String,
  third_party_request_type: String,
  message: String = ""
) : BaseResponse(third_party_request_type, tran_status, message)

Reversión

Se activa cuando hay que revertir una venta completada. Pasa el payment_reference del recibo digital para deshacer puntos, recompensas o cupones asociados.

Enviar una acción

val request = MarkAsReverseRequest(
  payment_reference = "payment-ref-from-digital-receipt",
  reversal_payment_reference = "", // opcional
  par = "V0010013000000000000000000001" // opcional
)

flowHandler.reverse(
  context,
  TransactionTypes.Void,
  request
).subscribe({ response ->
  // MarkAsReverseResponse
}) { throwable ->
  if (throwable is NotRegisteredFlowException) {
      // la aplicación de destino no ha registrado ninguna acción para este paso
  } else {
      // otra excepción
  }
}

Modelos de solicitud y respuesta

package com.zeal.zeal_communicator_sdk.communicationRequests

class MarkAsReverseRequest(
  var payment_reference: String, // referencia/id de pago de la venta original
  var reversal_payment_reference: String = "", // opcional
  var par: String? = null // opcional — referencia de cuenta de pago EMV
)
package com.zeal.zeal_communicator_sdk.communicationResponses

class MarkAsReverseResponse(
  tran_status: String,
  third_party_request_type: String,
  message: String = ""
) : BaseResponse(third_party_request_type, tran_status, message)