# Android App Integration

Accept NFC payments from your Android app using the **MONEI Pay Android SDK**. The SDK handles intent launching, result parsing, and error handling.

**Source:** [github.com/MONEI/monei-pay-android-sdk](https://github.com/MONEI/monei-pay-android-sdk)

No special signing needed

Uses standard Android intents — no special signing, entitlements, or platform approvals required.

## Payment Modes[​](#payment-modes "Direct link to Payment Modes")

The SDK supports two modes:

* **Direct** (`PaymentMode.DIRECT`) — Launches CloudCommerce directly. MONEI Pay is not required.
* **Via MONEI Pay** (`PaymentMode.VIA_MONEI_PAY`) — Launches MONEI Pay, which handles the NFC payment.

|                   | Direct                    | Via MONEI Pay                |
| ----------------- | ------------------------- | ---------------------------- |
| POS auth token    | Required                  | Required                     |
| MONEI Pay app     | Not needed                | Required                     |
| CloudCommerce app | Required                  | Not required                 |
| Best for          | CloudCommerce-only setups | Full MONEI Pay merchant flow |

## Download Required Apps[​](#download-required-apps "Direct link to Download Required Apps")

**MONEI Pay** (Via MONEI Pay mode)

[![Get MONEI Pay on Google Play](/img/google-play-icon.svg)](https://play.google.com/store/apps/details?id=com.monei.pay)

**CloudCommerce** (Direct mode)

[![Get CloudCommerce on Google Play](/img/google-play-icon.svg)](https://play.google.com/store/apps/details?id=com.mastercard.cpos)

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

* [MONEI account](https://dashboard.monei.com/register)
* Android 8.0+ (API 26), NFC-capable device
* POS auth token from your backend — see [Getting Started](https://docs.monei.com/monei-pay/app-integration/getting-started/.md)
* **Direct mode:** [CloudCommerce](https://play.google.com/store/apps/details?id=com.mastercard.cpos) installed
* **Via MONEI Pay mode:** [MONEI Pay](https://play.google.com/store/apps/details?id=com.monei.pay) installed

## Integration[​](#integration "Direct link to Integration")

### 1. Add the Dependency[​](#1-add-the-dependency "Direct link to 1. Add the Dependency")

* GitHub Packages (recommended)
* JitPack (no auth)

Requires a PAT with `read:packages` (or `GITHUB_TOKEN` in CI):

gradle.properties

```
gpr.user=YOUR_GITHUB_USERNAME

gpr.key=YOUR_GITHUB_TOKEN
```

settings.gradle.kts

```
dependencyResolutionManagement {

    repositories {

        google()

        mavenCentral()

        maven {

            url = uri("https://maven.pkg.github.com/MONEI/monei-pay-android-sdk")

            credentials {

                username = providers.gradleProperty("gpr.user")

                    .orElse(providers.environmentVariable("GITHUB_ACTOR"))

                    .get()

                password = providers.gradleProperty("gpr.key")

                    .orElse(providers.environmentVariable("GITHUB_TOKEN"))

                    .get()

            }

        }

    }

}
```

app/build.gradle.kts

```
dependencies {

    implementation("com.monei:monei-pay-sdk:0.2.0")

}
```

settings.gradle.kts

```
dependencyResolutionManagement {

    repositories {

        google()

        mavenCentral()

        maven { url = uri("https://jitpack.io") }

    }

}
```

app/build.gradle.kts

```
dependencies {

    implementation("com.github.MONEI.monei-pay-android-sdk:sdk:v0.2.0")

}
```

[![](https://jitpack.io/v/MONEI/monei-pay-android-sdk.svg)](https://jitpack.io/#MONEI/monei-pay-android-sdk)

### 2. Configure AndroidManifest[​](#2-configure-androidmanifest "Direct link to 2. Configure AndroidManifest")

AndroidManifest.xml

```
<manifest xmlns:android="http://schemas.android.com/apk/res/android">



    <queries>

        <intent>

            <action android:name="com.monei.pay.ACCEPT_PAYMENT" />

        </intent>

        <package android:name="com.mastercard.cpos" />

        <intent>

            <action android:name="android.intent.action.VIEW" />

            <data android:scheme="cloud_payment" />

        </intent>

    </queries>



</manifest>
```

### 3. Accept a Payment[​](#3-accept-a-payment "Direct link to 3. Accept a Payment")

* Direct Mode
* Via MONEI Pay

```
import com.monei.pay.sdk.MoneiPay

import com.monei.pay.sdk.PaymentMode

import com.monei.pay.sdk.MoneiPayException



try {

    val result = MoneiPay.acceptPayment(

        context = this,

        token = "eyJ...",

        amount = 1500,

        description = "Order #123",

        customerName = "John Doe",

        customerEmail = "john@example.com",

        customerPhone = "+34600000000",

        mode = PaymentMode.DIRECT

    )



    if (result.success) {

        println("Payment approved: ${result.transactionId}")

        println("Card: ${result.cardBrand} ${result.maskedCardNumber}")

    }

} catch (e: MoneiPayException.CloudCommerceNotInstalled) {

    // Prompt user to install CloudCommerce

} catch (e: MoneiPayException.PaymentCancelled) {

    // User cancelled

} catch (e: MoneiPayException.InvalidToken) {

    // Token expired or invalid

} catch (e: MoneiPayException.PaymentFailed) {

    println("Payment failed: ${e.reason}")

} catch (e: MoneiPayException) {

    println("Error: ${e.message}")

}
```

```
import com.monei.pay.sdk.MoneiPay

import com.monei.pay.sdk.PaymentMode

import com.monei.pay.sdk.MoneiPayException



try {

    val result = MoneiPay.acceptPayment(

        context = this,

        token = "eyJ...",

        amount = 1500,

        description = "Order #123",

        customerName = "John Doe",

        customerEmail = "john@example.com",

        customerPhone = "+34600000000",

        mode = PaymentMode.VIA_MONEI_PAY

    )



    if (result.success) {

        println("Payment approved: ${result.transactionId}")

        println("Card: ${result.cardBrand} ${result.maskedCardNumber}")

    }

} catch (e: MoneiPayException.MoneiPayNotInstalled) {

    // Prompt user to install MONEI Pay

} catch (e: MoneiPayException.PaymentCancelled) {

    // User cancelled

} catch (e: MoneiPayException.InvalidToken) {

    // Token expired or invalid

} catch (e: MoneiPayException) {

    println("Payment failed: ${e.message}")

}
```

### SDK Reference[​](#sdk-reference "Direct link to SDK Reference")

#### `MoneiPay.acceptPayment(...)`[​](#moneipayacceptpayment "Direct link to moneipayacceptpayment")

Suspending function — call from a coroutine scope.

| Parameter       | Type          | Required | Description                                |
| --------------- | ------------- | -------- | ------------------------------------------ |
| `context`       | `Context`     | Yes      | Activity or Application context            |
| `token`         | `String`      | Yes      | Raw JWT auth token (no `"Bearer "` prefix) |
| `amount`        | `Int`         | Yes      | Amount in cents                            |
| `description`   | `String?`     | No       | Payment description                        |
| `customerName`  | `String?`     | No       | Customer name                              |
| `customerEmail` | `String?`     | No       | Customer email                             |
| `customerPhone` | `String?`     | No       | Customer phone                             |
| `mode`          | `PaymentMode` | No       | `DIRECT` (default) or `VIA_MONEI_PAY`      |

#### `PaymentResult`[​](#paymentresult "Direct link to paymentresult")

| Property           | Type      | Description                            |
| ------------------ | --------- | -------------------------------------- |
| `transactionId`    | `String`  | MONEI transaction ID                   |
| `success`          | `Boolean` | Whether the payment was approved       |
| `amount`           | `Int?`    | Payment amount in cents                |
| `cardBrand`        | `String?` | Card brand (e.g. `visa`, `mastercard`) |
| `maskedCardNumber` | `String?` | Masked card number (e.g. `****1234`)   |

#### Error Types[​](#error-types "Direct link to Error Types")

| Exception                   | Description                                    |
| --------------------------- | ---------------------------------------------- |
| `MoneiPayNotInstalled`      | MONEI Pay not installed (VIA\_MONEI\_PAY mode) |
| `CloudCommerceNotInstalled` | CloudCommerce not installed (DIRECT mode)      |
| `PaymentInProgress`         | Another payment is already active              |
| `PaymentCancelled`          | User cancelled                                 |
| `PaymentFailed`             | Payment declined or failed (has `reason`)      |
| `InvalidParameters`         | Invalid input (e.g. non-positive amount)       |
| `InvalidToken`              | Auth token invalid or expired                  |

***

## Manual Integration (Intent)[​](#manual-integration-intent "Direct link to Manual Integration (Intent)")

For integration without the SDK using Android intents directly.

Show manual intent integration

### Configure Your Manifest[​](#configure-your-manifest "Direct link to Configure Your Manifest")

AndroidManifest.xml

```
<manifest xmlns:android="http://schemas.android.com/apk/res/android">



    <uses-permission android:name="com.monei.pay.permission.ACCEPT_PAYMENT" />



    <queries>

        <intent>

            <action android:name="com.monei.pay.ACCEPT_PAYMENT" />

        </intent>

    </queries>



</manifest>
```

### Launch the Payment Intent[​](#launch-the-payment-intent "Direct link to Launch the Payment Intent")

```
class MainActivity : AppCompatActivity() {



    private val paymentLauncher = registerForActivityResult(

        ActivityResultContracts.StartActivityForResult()

    ) { result ->

        when (result.resultCode) {

            RESULT_OK -> handleSuccess(result.data)

            RESULT_CANCELED -> handleError(result.data)

        }

    }



    fun acceptPayment(amountInCents: Int) {

        val intent = Intent("com.monei.pay.ACCEPT_PAYMENT").apply {

            setPackage("com.monei.moneibusiness")

            putExtra("amount_cents", amountInCents)

            putExtra("auth_token", "eyJ...")

        }



        if (intent.resolveActivity(packageManager) == null) {

            return

        }



        paymentLauncher.launch(intent)

    }

}
```

### Handle the Result[​](#handle-the-result "Direct link to Handle the Result")

```
private fun handleSuccess(data: Intent?) {

    val success = data?.getBooleanExtra("success", false) ?: false

    val transactionId = data?.getStringExtra("transaction_id")

    val amount = data?.getIntExtra("amount", 0)

    val cardBrand = data?.getStringExtra("card_brand")

    val maskedCard = data?.getStringExtra("masked_card_number")

}



private fun handleError(data: Intent?) {

    val errorCode = data?.getStringExtra("error_code") ?: "UNKNOWN"

    val errorMessage = data?.getStringExtra("error_message") ?: "Payment failed"

}
```

### Intent Parameters[​](#intent-parameters "Direct link to Intent Parameters")

#### Request Extras[​](#request-extras "Direct link to Request Extras")

| Extra            | Type   | Required | Description                                       |
| ---------------- | ------ | -------- | ------------------------------------------------- |
| `amount_cents`   | Int    | Yes      | Payment amount in cents (e.g. `1500` = 15.00 EUR) |
| `auth_token`     | String | Yes      | POS auth token (raw JWT)                          |
| `description`    | String | No       | Payment description                               |
| `customer_name`  | String | No       | Customer name                                     |
| `customer_email` | String | No       | Customer email                                    |
| `customer_phone` | String | No       | Customer phone                                    |

#### Result Extras (RESULT\_OK)[​](#result-extras-result_ok "Direct link to Result Extras (RESULT_OK)")

| Extra                | Type    | Description                             |
| -------------------- | ------- | --------------------------------------- |
| `transaction_id`     | String  | MONEI transaction ID                    |
| `success`            | Boolean | `true` if approved, `false` if declined |
| `amount`             | Int     | Payment amount in cents                 |
| `card_brand`         | String  | Card brand (e.g. `visa`, `mastercard`)  |
| `masked_card_number` | String  | Masked card number (e.g. `****1234`)    |

#### Result Extras (RESULT\_CANCELED)[​](#result-extras-result_canceled "Direct link to Result Extras (RESULT_CANCELED)")

| Extra           | Type   | Description                                             |
| --------------- | ------ | ------------------------------------------------------- |
| `error_code`    | String | Error code (e.g. `PAYMENT_FAILED`, `NOT_AUTHENTICATED`) |
| `error_message` | String | Human-readable error description                        |

## Example App[​](#example-app "Direct link to Example App")

The [`examples/merchant-demo/`](https://github.com/MONEI/monei-pay-android-sdk/tree/master/examples/merchant-demo) directory contains a minimal app demonstrating the full flow. Run `./gradlew assembleDebug` and install on an NFC-capable device. The project uses `includeBuild` to reference the SDK locally, so SDK changes apply immediately.

## Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting")

### `CloudCommerceNotInstalled`[​](#cloudcommercenotinstalled "Direct link to cloudcommercenotinstalled")

CloudCommerce is a separate app from MONEI Pay. Install from [Google Play](https://play.google.com/store/apps/details?id=com.mastercard.cpos) and verify your manifest includes the `<package>` and `cloud_payment://` scheme in `<queries>`.

### `MoneiPayNotInstalled`[​](#moneipaynotinstalled "Direct link to moneipaynotinstalled")

Install MONEI Pay from [Google Play](https://play.google.com/store/apps/details?id=com.monei.pay). Verify your manifest includes the `com.monei.pay.ACCEPT_PAYMENT` action in `<queries>`.

### `InvalidToken`[​](#invalidtoken "Direct link to invalidtoken")

The POS auth token has a 24h lifetime. Generate a fresh token from your backend. Pass the raw JWT string — not `"Bearer ..."`.

### Payment fails on API 30+[​](#payment-fails-on-api-30 "Direct link to Payment fails on API 30+")

Android 11+ requires `<queries>` for package visibility. Ensure your manifest has the full queries block from [Configure AndroidManifest](#2-configure-androidmanifest).

### Dependency resolution fails[​](#dependency-resolution-fails "Direct link to Dependency resolution fails")

* **JitPack:** Add `google()`, `mavenCentral()`, and `https://jitpack.io` to `settings.gradle.kts` under `dependencyResolutionManagement`.
* **GitHub Packages:** Check `gpr.user` / `gpr.key` in `gradle.properties` and the `maven.pkg.github.com/MONEI/monei-pay-android-sdk` repository block.
