MPoC SDK
API Reference
EMV Transaction

EMV Transaction

Overview

The SDK has to be initialized before use. First initialization will trigger SDK to register online. Therefore, you have to make sure your device being connected before first initialization.

Launch Transaction by Activity Call

It's simple to launch a card reading transaction with MineHades MPoC SDK. The SDK will launch an activity to waiting card tapping. and it will return the card data once reading success. sometimes, the reading process may additionally launch PIN Entry (if CVM indicates PIN is required). PINBLOCK and PIN Key ID will be returned if PIN is entered. This API allows merchants to start a contactless EMV transaction by either:

  • Launching your own custom Activity (with a fully or partially customizable UI), or
  • Using the SDK’s default UI.

Tip: If you choose to use a custom Activity, you need to specify it in your AndroidManifest.xml as:

<activity
  android:name=".YourCustomPaymentActivity"
  android:process="com.theminesec.MineHades.MPoCSdk" />

an example is provided below.

launcher = registerForActivityResult(
  MineSecPaymentActivity.contract(CustomPaymentActivity::class.java)
) {
  when (it) {
    is MPoCResult.Success -> {
      //card reading transaction succeed
      sdkViewModel.writeMessage("${it.javaClass.simpleName} \n" + gson.toJson(it))
    }
    is MPoCResult.Failure -> {
      //card reading transaction failed
      sdkViewModel.writeMessage("transaction fails ${it.code} ${it.message} contextu=${it.contextual}")
    }
  }
}
 
// NOTE: PIN Pad configuration is totally optional if you dont want to change some display features.
// with customized PIN entry UI
val pinPadConfig = PinPadConfig(
  pinPadStyle = PinPadStyle(
    backgroundColor = Color.LightGray.toArgb(),
    amountStyle = getOswaldBold30(this@MainActivity),
    digitStyle = getOswaldBold30(this@MainActivity),
    descriptionStyle = getOswaldBold30(this@MainActivity),
    buttonsColor = ButtonsColor(
      abortBtn = Color.DarkGray.toArgb(),
      confirmBtn = Color.Blue.toArgb(),
      clearBtn = Color.Red.toArgb(),
    )
  ),
  //Shuffle,Fixed or Moving
  pinEntryMode = PinEntryMode.FIXED,
  pinEntryDetails = PinEntryDetails(
    pinDescription = "Your PIN Please!",
    amount = "100.75 USD",
    description = "This is payment description",
    supportPINBypass = false
  )
)
val transactionDto = MhdEmvTransactionDto(
  txnAmount = sdkViewModel.amount.toLong(),
  txnCurrencyText = "USD",
  pinpadConfig = gson.toJson(pinPadConfig) // this is optional if you dont want to set pinPad style
)
launcher.launch(transactionDto)

Default UIs

If you do not customize the card reading UI, the default UI will be as follows:

Preparation ScreenAwaiting Card Screen
PreparationAwaiting

Legacy Transaction API

There is a legacy API which launch a payment request via MPoCAPI.startEmvTransaction instead of activity call. This function will be deprecated in next release.

fun startEmvTransaction(
  data: MhdEmvTransactionDto,
  callback: (MPoCResult<MhdEmvTransResult>) -> Unit
)

How to load a HMAC key for hashing card data ?

The SDK supports user to hash(tokenize) the card data. Please refer to the data models MhdEmvTransactionDto field wrappedHMacKey. for data returned, please refer to MhdEmvTransResult field cardHashValue.

  • how to wrap a HMACKey using RSA? We support to wrap a HMAC key that is less than 256 bytes(2048bits) by using the SDK KEK(RSA Public Key). here is an example
/* step 1. read the X509Certificate PEM from MPoCAPI.getSdkInfo()*/
fun readPublicKeyCert(): String {
        return when (val result = MPoCAPI.getSdkInfo()) {
            is MPoCResult.Success -> result.data.kekCert
            else -> ""
        }
    }
 
/* step 2. convert the PEM file to X509Certificate*/
fun PemtoX509Certificate(pem:String):X509Certificate {
  val cert = pem.replace("-----BEGIN CERTIFICATE-----", "")
    .replace("-----END CERTIFICATE-----", "")
    .replace("\n", "")
    .replace("\r", "").trim()
    val bytes = Base64.getDecoder().decode(cert)
    val cf = CertificateFactory.getInstance("X.509")
    val certObj = cf.generateCertificate(ByteArrayInputStream(bytes))
    return certObj as? X509Certificate
      ?: throw Exception("convert X509Cert fails")
}
 
 
/* step3. wrap HMAC Key with RSA Public Key. Please be well noted:
*         encrypted data should be encoded as base64 String
*/
fun wrapHMACKey(hmacKey:ByteArray, rsaKey:X509Certicicate):String{
  val oaepSpec = OAEPParameterSpec(
    "SHA-256", "MGF1",
    MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT
  )
  val cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding")
    .apply {
      init(Cipher.ENCRYPT_MODE, rsaKey.publicKey, oaepSpec)
    }
  return cipher.doFinal(hmacKey).let{
    Base64.getEncoder().encodeToString(it)
  }
}
 
/* step 4. please provide this wrapped result to MhdEmvTransactionDto object */
val transactionDto = MhdEmvTransactionDto(
  // ...
  wrappedHMacKey = base64WrappedKey
  // ...
)