2 - Realizar Pagamento

Realize pagamentos por aproximação (Tap to Pay) utilizando o SDK Android da Zoop.

Realize pagamentos por aproximação (Tap to Pay) utilizando o SDK Android da Zoop. Esta página cobre as 3 etapas necessárias para processar um pagamento:

① Inicialização do Kernel  →  ② Configuração do SDK  →  ③ Pagamento
   kernelInitialize()            setConfig()                pay()

Inicialização do Kernel

O kernelInitialize() é o primeiro método obrigatório a ser chamado antes de usar qualquer funcionalidade do SDK. Implemente-o na classe Application do seu app, dentro do onCreate().

⚠️

Chame kernelInitialize() logo após super.onCreate(). Caso contrário, os processos internos do SDK podem não funcionar corretamente.

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // Garante que o código abaixo só execute no processo da sua aplicação
        if (!TapOnPhone.kernelInitialize(this))
            return

        // Restante da inicialização do seu app...
    }
}
Por que o if (!kernelInitialize()) return é necessário?

✅ Retornotrue

O processo pertence à sua aplicação (Host Application). O código deve continuar executando normalmente.

⛔ Retornofalse

O processo pertence ao SDK (Crypto Process). O código deve retornar imediatamente com return para evitar inicialização duplicada.

Durante a inicialização, o SDK cria um processo criptográfico (Crypto Process) em background, fazendo com que o onCreate() seja chamado mais de uma vez. O retorno booleano permite distinguir o processo:

✅ Retorno true — Processo da sua aplicação. Continue normalmente.

⛔ Retorno false — Processo do SDK (Crypto). Retorne imediatamente.

Application.onCreate()
  │
  ├─ super.onCreate()
  │
  ├─ TapOnPhone.kernelInitialize(this)
  │     │
  │     ├─ retorna true  → Host Application  → continua a inicialização do app
  │     │
  │     └─ retorna false → Crypto Process     → return (encerra imediatamente)
  │
  └─ Restante da inicialização do app (só executa se true)

Sem essa verificação, o onCreate() executaria duas vezes — uma para cada processo — causando erros e comportamento inconsistente.


Definir configurações do SDK

O método TapOnPhone.setConfig() permite configurar credenciais, timeout, volume do beep, tema e comportamento de telas de erro em uma única chamada.

⚠️

Chame TapOnPhone.setConfig() após TapOnPhone.kernelInitialize() e antes da inicialização do terminal. Sem essa chamada, o SDK não funcionará corretamente.

Estrutura

data class ConfigParameters(
    val context: Context,
    val credentials: Credentials,
    val sdkConfig: SdkConfig
)
data class SdkConfig(
    val theme: TapOnPhoneTheme? = null,
    val timeout: TimeoutConfig? = null,
    val beepVolume: BeepVolumeConfig? = null,
    val showErrorScreen: Boolean? = null
)

Configurações disponíveis

ParâmetroDescriçãoValores
timeoutTempos de timeout para cada etapa da transaçãoVide Configurações de timeout
beepVolumeVolume do beep do dispositivo durante a transaçãoVide Volume do Beep
themeCores e aparência da interface do SDKVide Configurações de tema
showErrorScreenExibir telas de erro quando ocorrerem falhastrue (padrão) ou false
Exemplo completo de configuração
// Credenciais
val credentials = Credentials(
    clientId = "seu_client_id",
    clientSecret = "seu_client_secret",
    marketplace = "seu_marketplace",
    seller = "seu_seller",
    accessKey = "seu_access_key",
    attestation = Attestation(
        clientId = "seu_client_id_attestation",
        clientSecret = "seu_client_secret_attestation"
    )
)

// Timeout
val timeoutConfig = TimeoutConfig(
    discoveryTimeout = 30_000,     // Tempo para detectar o cartão (ms)
    processingTimeout = 20_000,    // Tempo de processamento do kernel (ms)
    networkTimeout = 30_000,       // Tempo de comunicação com o servidor (ms)
    totalElapsedTimeout = 180_000  // Tempo total máximo da transação (ms)
)

// Tema
val theme = TapOnPhoneTheme(
    backgroundColor = Color.parseColor("#FFFFFFFF"),
    amountTextColor = Color.parseColor("#000000"),
    paymentTypeTextColor = Color.parseColor("#FFFF0000"),
    statusTextColor = Color.parseColor("#FF000000"),
    statusBarColor = Color.parseColor("#FF7300")
)

// Aplicar configurações
TapOnPhone.setConfig(
    ConfigParameters(
        context = context,
        credentials = credentials,
        sdkConfig = SdkConfig(
            timeout = timeoutConfig,
            theme = theme,
            beepVolume = BeepVolumeConfig(beepVolume = 0.5f),
            showErrorScreen = true
        )
    )
)
🔒

Nunca inclua credenciais diretamente no código-fonte. Armazene-as em variáveis de ambiente ou em um serviço de gerenciamento de segredos no backend e injete-as em tempo de execução.


Pagamento

Utilize o método TapOnPhone.pay() para realizar pagamentos por aproximação.

💡

Se o dispositivo ainda não estiver inicializado, o SDK executará initialize() e activateSession() automaticamente antes do pagamento — o que pode adicionar alguns segundos de espera. Para evitar esse tempo, chame-os previamente.

Parâmetros do pagamento

O método pay() recebe um objeto PaymentRequest:

data class PaymentRequest(
    val amount: Long,
    val paymentType: PaymentType,
    val installments: Int? = null,
    val referenceId: String? = null,
    val metadata: String? = null
)
ParâmetroTipoDescriçãoExemplo
amountLongValor da transação em centavos.10000 (R$ 100,00)
paymentTypePaymentTypeTipo do pagamento.PaymentType.CREDIT
installmentsInt?Quantidade de parcelas (opcional).2
referenceIdString?Identificador próprio do parceiro (opcional, máx. 50 caracteres)."237ab31-g99c-..."
metadataString?Metadados em JSON fornecidos pelo parceiro (opcional, máx. 512 caracteres).Vide Metadados
Tipos de pagamento e metadados

PaymentType

enum class PaymentType {
    CREDIT,  // Crédito
    DEBIT,   // Débito
    PIX      // Pix
}

Metadados em JsonObject

val metadata = buildJsonObject {
    put("clientId", "1234")
    put("name", "John Doe")
}

Exemplo completo

Chamada do pay() com tratamento de sucesso, erro e eventos:

TapOnPhone.pay(
    request = PaymentRequest(
        amount = 10000,  // R$ 100,00
        paymentType = PaymentType.CREDIT,
        installments = 2,
        referenceId = UUID.randomUUID().toString(),
        metadata = """
            {
                "clientId": "1234",
                "name": "John Doe"
            }
        """
    ),
    onSuccess = { result ->
        println("Pagamento Aprovado! Id: ${result.transactionId}")
        println("Bandeira: ${result.cardBrand}")
        println("Bin: ${result.binNumber}")
        result.paymentDevice?.let {
            println("Dispositivo: $it")
        }
    },
    onError = { error ->
        when (error.type) {
            ErrorResponse.ErrorType.Payment -> {
                val paymentError = error.error as? PaymentErrorResponse
                paymentError?.let {
                    println("Pagamento negado - id: ${it.transactionId}")
                    println("Mensagem: ${it.message}")
                    println("Código: ${it.code}")
                    println("Descrição: ${it.description}")

                    // Informações de attestation (se disponíveis)
                    it.attestationStatus.forEach { attestation ->
                        Log.d("status", attestation.status)
                        Log.d("timestamp", attestation.timestampUtc)
                        attestation.outcomes.forEach { outcome ->
                            Log.d(
                                "outcome",
                                "moniker[${outcome.moniker}] code[${outcome.statusCode}] reason[${outcome.reason}]"
                            )
                        }
                    }

                    // Código de erro da Google Play Integrity API (se disponível)
                    it.integrityErrorCode?.let { integrityError ->
                        Log.e("Payment", "Integrity Error Code: ${integrityError.code}")
                        Log.e("Payment", "Integrity Error Description: ${integrityError.description}")
                    }
                }
            }
            ErrorResponse.ErrorType.Session -> {
                val sessionError = error.error as? SessionErrorResponse
                sessionError?.let {
                    println("Erro de sessão: ${it.message}")
                    it.integrityErrorCode?.let { integrityError ->
                        Log.e("Payment", "Integrity Error Code: ${integrityError.code}")
                    }
                }
            }
            else -> {
                // Tratar outros tipos de erro
            }
        }
    },
    onEvent = { event ->
        Log.d("Payment", "Evento: ${event.name}")
    }
)

Respostas

Sucesso — PaymentApprovedResponse

data class PaymentApprovedResponse(
    val transactionId: String,   // ID da transação na Zoop
    val referenceId: String,     // Seu ID para a transação, se fornecido no request
    val cardBrand: CardBrand,    // Bandeira do cartão
    val binNumber: String,       // Primeiros dígitos do cartão
    val paymentDevice: String?   // Tipo de dispositivo (CARD, WATCH), se disponível
)

Erro — Tratamento por tipo

O callback onError recebe um ErrorResponse unificado. Verifique o type para acessar detalhes específicos:

onError = { error ->
    when (error.type) {
        ErrorResponse.ErrorType.Payment -> {
            val paymentError = error.error as? PaymentErrorResponse
            // Detalhes do erro de pagamento
        }
        ErrorResponse.ErrorType.Session -> {
            val sessionError = error.error as? SessionErrorResponse
            // Detalhes do erro de sessão
        }
        else -> {
            // Outros tipos de erro
        }
    }
}

Detalhes do erro — PaymentErrorResponse

Contém informações detalhadas sobre a falha:

data class PaymentErrorResponse(
    val transactionId: String?,       // ID da transação na Zoop (null se falhou antes do envio)
    val referenceId: String?,         // Seu ID para a transação
    val message: String?,             // Mensagem de erro para o usuário
    val code: Int?,                   // Código de erro
    val source: String?,              // Onde ocorreu o erro
    val description: String?,         // Descrição detalhada do erro
    val errorSource: String?,         // Origem: sdk, backend, kernel, acquirer
    val operationType: String?,       // Tipo de operação: pay, activation
    val kernel: KernelError?,         // Detalhes do erro do kernel
    val attestationStatus: Array<AttestationStatus>,  // Informações de attestation
    val binNumber: String?,           // Primeiros dígitos do cartão
    val paymentDevice: String?,       // Tipo de dispositivo (CARD, WATCH)
    val integrityErrorCode: IntegrityErrorCode?,  // Erro da Google Play Integrity API
    val zoopDescription: String?      // Descrição do erro retornada pela Zoop
)
Objetos aninhados de PaymentErrorResponse
data class KernelError(
    val code: Int,          // Código do erro kernel
    val name: String,       // Nome do erro kernel
    val description: String // Descrição do erro kernel
)
data class AttestationStatus(
    val outcomes: Array<Outcome>,
    val status: String,
    val timestampUtc: String
) {
    data class Outcome(
        val moniker: String,
        val reason: String,
        val statusCode: Int
    )
}
CampoDescrição
transactionIdID da transação na Zoop. Será null se a falha ocorreu antes do envio ao servidor.
codeCódigo numérico do erro. Consulte a referência de erros para detalhes.
errorSourceIndica a origem do erro: sdk, backend, kernel ou acquirer.
kernelPresente quando o erro é do kernel. Contém código, nome e descrição da falha.
attestationStatusInformações de attestation quando o erro está relacionado à segurança do dispositivo.
integrityErrorCodeCódigo de erro da Google Play Integrity API, quando disponível.