Docs · Integration guides

Android Intent integration

Launch the miaPOS Android app from an external cash register app on the same device. Standard Android Intent mechanism — no REST calls, no network on the cashier side. Payment is authorised in miaPOS, and the result is returned as an Activity result.

AudienceAndroid developer
DifficultyBasic
LanguageKotlin / Java
Updated2026-06-25

When to use this

You already have a cash register / ECR app (or you are writing one) that runs on the same Android device as miaPOS — a Sunmi terminal, a smart POS, or a merchant tablet. You need miaPOS to accept the payment and hand the result back to your cashier UI. Use Android Intent. This is the fastest integration path for on-device co-existence — no HTTPS setup, no credentials to manage in your app.

Not on the same device? If your cash register runs on a Windows PC or a separate tablet talking to a POS terminal over the network, use the POS API instead. Android Intent is strictly for same-device flows.

Action & app id

Every string used in the Intent — action and every extra key — is prefixed with the miaPOS app id. Two builds exist:

  • md.finergy.miapos — release build (production).
  • md.finergy.miapos.debug — debug build (development on the same device).

The action to launch payment is <app_id>.action.MIA_PAY. Start the Intent for a result — either through ActivityResultContracts.StartActivityForResult (recommended) or the legacy Activity.startActivityForResult.

Request extras

Three required extras, all with the <app_id>.extra. prefix:

KeyTypeDescriptionExample
MIA_PAY_REQUEST_ID String (UUID) Idempotency key for this payment request. Your app generates a fresh UUID per payment. c8c5584f-7a4a-…
MIA_PAY_AMOUNT Float Amount to charge, in the currency below. 123.54
MIA_PAY_CURRENCY String ISO 4217 currency code. Currently MDL only. MDL

Response extras

miaPOS returns the following extras in the result Intent:

KeyTypeWhen presentDescription
MIA_PAY_REQUEST_ID String (UUID) Always Echoes back the request id.
MIA_PAY_STATUS String Always One of success, failed.
MIA_PAY_TX_INFO String (JSON) Only on success Transaction info: amount, currency, date, mcc. Example: {"amount":123.45,"currency":"MDL","date":"2024-04-04T10:49:54","mcc":"1234"}.
MIA_PAY_ERROR_REASON String Only on failed One of validation_error, generate_error, expired, canceled, wait_pay_error. New values can be added in the future — treat the enum as open.

If the user backs out before finishing, the launcher receives an activity resultCode that is not RESULT_OK. Treat that as a cancellation.

Kotlin example

class CashboxActivity : ComponentActivity() {

    companion object {
        // "md.finergy.miapos" for release build
        private const val MIA_APP_ID = "md.finergy.miapos.debug"

        private const val ACTION_MIA_PAY               = "$MIA_APP_ID.action.MIA_PAY"
        private const val EXTRA_MIA_PAY_REQUEST_ID     = "$MIA_APP_ID.extra.MIA_PAY_REQUEST_ID"
        private const val EXTRA_MIA_PAY_AMOUNT         = "$MIA_APP_ID.extra.MIA_PAY_AMOUNT"
        private const val EXTRA_MIA_PAY_CURRENCY       = "$MIA_APP_ID.extra.MIA_PAY_CURRENCY"
        private const val EXTRA_MIA_PAY_STATUS         = "$MIA_APP_ID.extra.MIA_PAY_STATUS"
        private const val EXTRA_MIA_PAY_TX_INFO        = "$MIA_APP_ID.extra.MIA_PAY_TX_INFO"
        private const val EXTRA_MIA_PAY_ERROR_REASON   = "$MIA_APP_ID.extra.MIA_PAY_ERROR_REASON"
    }

    private val launcher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { activityResult ->
        when (activityResult.resultCode) {
            RESULT_OK -> handlePaymentResult(activityResult.data)
            else      -> Log.d("PaymentResult", "Operation canceled")
        }
    }

    fun pay(amount: Float, currency: String = "MDL") {
        try {
            launcher.launch(Intent().apply {
                action = ACTION_MIA_PAY
                putExtra(EXTRA_MIA_PAY_REQUEST_ID, UUID.randomUUID().toString())
                putExtra(EXTRA_MIA_PAY_AMOUNT, amount)
                putExtra(EXTRA_MIA_PAY_CURRENCY, currency)
            })
        } catch (e: ActivityNotFoundException) {
            // miaPOS app is not installed on this device
        }
    }

    private fun handlePaymentResult(intent: Intent?) {
        if (intent == null) return
        val status      = intent.getStringExtra(EXTRA_MIA_PAY_STATUS)
        val requestId   = intent.getStringExtra(EXTRA_MIA_PAY_REQUEST_ID)
        val txInfoJson  = intent.getStringExtra(EXTRA_MIA_PAY_TX_INFO)
        val errorReason = intent.getStringExtra(EXTRA_MIA_PAY_ERROR_REASON)
        Log.d("PaymentResult", "status=$status requestId=$requestId txInfo=$txInfoJson error=$errorReason")
    }
}

Handling errors

Two failure classes to plan for on the cashier side:

  • ActivityNotFoundException — the miaPOS app is not installed on this device. Prompt the merchant to install miaPOS from Google Play or (for pre-provisioned Sunmi/SmartOne devices) contact support.
  • MIA_PAY_STATUS = "failed" — miaPOS launched but the payment did not complete. Read MIA_PAY_ERROR_REASON to decide whether to retry (expired, wait_pay_error) or fail hard (validation_error).

Testing

Point MIA_APP_ID at md.finergy.miapos.debug while you develop against the debug build of miaPOS. Flip to md.finergy.miapos for release. Nothing else in the contract changes between the two builds. The debug build points at the sandbox environment configured on the device.

What this integration does not cover

  • Refunds, returns, shift management, receipts — those are cashier operations inside miaPOS itself, not exposed via Intent. Use the POS API if you need programmatic access to those.
  • Remote / cross-device flows — Intent is on-device only. Use the POS API or E-comm API for remote payment initiation.
  • Currencies other than MDL — currently the only supported value.