# PAX D135 Android Quickstart

This guide shows how to build in-person payment flows on Android using the Finix Android SDK with the PAX D135 Bluetooth card reader.

## Environment Designation

When ordering a PAX D135 your Finix point of contact will have you designate which environment you wish to use it in. Finix will notify you which device serial number corresponds to each environment.

### Device Designation

A D135 device can be designated to be used for either Sandbox development or Production transaction processing **but not both**. We recommend requesting enough devices to utilize in both your Sandbox development and Production testing.

## Prerequisites

- Your PAX D135 device is fully charged.
- Android 8.0 (API level 26) or higher.

### Charging the Device

Charge the battery only with PAX-approved power supplies. Using others may damage the product and void the warranty.

Charging time must not exceed 24 hours. If the battery is empty, recharge it fully, then disconnect the device to avoid shortening its life.

## Determine Which Type of Integration You Prefer

The SDK supports the use of either `ROLE_PARTNER` or `ROLE_MERCHANT` credentials. If you would like to scope your device to a single merchant it is recommended to use `ROLE_MERCHANT` credentials. If you plan to use the device across multiple merchants you should use `ROLE_PARTNER` credentials.

Note that the following functionality requires the use of `ROLE_PARTNER` credentials.

- [Split Transactions](https://docs.finix.com/guides/online-payments/payment-features/split-transactions)

### How to Create ROLE_MERCHANT Credentials

The following outlines how to create `ROLE_MERCHANT` credentials. Once created, you can use these credentials across multiple devices as long as the devices are associated to the same Merchant.

**POST** /identities

- **Sandbox server**  
  `https://finix.sandbox-payments-api.com/identities`

**cURL**

```bash
curl -i -X POST \
  -u USfdccsr1Z5iVbXDyYt7hjZZ:313636f3-fac2-45a7-bff7-a334b93e7bda \
  https://finix.sandbox-payments-api.com/identities \
  -H 'Content-Type: application/json' \
  -H 'Finix-Version: 2022-02-01' \
  -d '{
    "additional_underwriting_data": {
      "annual_ach_volume": 0,
      "average_ach_transfer_amount": 0,
      "average_card_transfer_amount": 0,
      "business_description": "string",
      "card_volume_distribution": {
        "card_present_percentage": 0,
        "ecommerce_percentage": 0,
        "mail_order_telephone_order_percentage": 0
      },
      "credit_check_allowed": true,
      "credit_check_ip_address": "string",
      "credit_check_timestamp": "string",
      "credit_check_user_agent": "string",
      "merchant_agreement_accepted": true,
      "merchant_agreement_ip_address": "string",
      "merchant_agreement_timestamp": "string",
      "merchant_agreement_user_agent": "string",
      "refund_policy": "MERCHANDISE_EXCHANGE_ONLY",
      "volume_distribution_by_business_type": {
        "business_to_business_volume_percentage": 0,
        "business_to_consumer_volume_percentage": 0,
        "consumer_to_consumer_volume_percentage": 0,
        "other_volume_percentage": 0,
        "person_to_person_volume_percentage": 0
      }
    },
    "entity": {
      "ach_max_transaction_amount": 0,
      "amex_mid": 0,
      "annual_card_volume": 0,
      "business_address": {
        "city": "string",
        "country": "string",
        "line1": "string",
        "line2": "string",
        "postal_code": "string",
        "region": "string"
      },
      "business_name": "string",
      "business_phone": "string",
      "business_tax_id": "string",
      "business_type": "ASSOCIATION_ESTATE_TRUST",
      "default_statement_descriptor": "string",
      "discover_mid": 0,
      "dob": {
        "day": 1,
        "month": 1,
        "year": 1900
      },
      "doing_business_as": "string",
      "email": "string",
      "first_name": "string",
      "has_accepted_credit_cards_previously": true,
      "incorporation_date": {
        "day": 0,
        "month": 0,
        "year": 0
      },
      "last_name": "string",
      "max_transaction_amount": 0,
      "mcc": "string",
      "ownership_type": "PRIVATE",
      "personal_address": {
        "line1": "string",
        "line2": "string",
        "city": "string",
        "region": "string",
        "postal_code": "string",
        "country": "ABW"
      },
      "phone": "string",
      "principal_percentage_ownership": 0,
      "short_business_name": "string",
      "tax_authority": "string",
      "tax_id": "string",
      "title": "string",
      "url": "string"
    },
    "identity_roles": [
      "SELLER"
    ],
    "tags": {
      "property1": "string",
      "property2": "string"
    },
    "type": "BUSINESS"
  }'
```

**Example**:

```json
{
  "id": "USoR21bF52KLZpbQCptrexpH",
  "created_at": "2025-12-08T18:35:51.41Z",
  "updated_at": "2025-12-08T18:35:51.41Z",
  "created_by": "USfdccsr1Z5iVbXDyYt7hjZZ",
  "email": null,
  "enabled": true,
  "first_name": null,
  "identity": "IDjvxGeXBLKH1V9YnWm1CS4n",
  "last_name": null,
  "last_used_date": null,
  "password": "f2fd7118-66c3-495c-8942-8178e0ea9d0c",
  "role": "ROLE_MERCHANT",
  "tags": {},
  "_links": {
    "self": {
      "href": "https://finix.sandbox-payments-api.com/users/USoR21bF52KLZpbQCptrexpH"
    },
    "applications": {
      "href": "https://finix.sandbox-payments-api.com/applications"
    },
    "application": {
      "href": "https://finix.sandbox-payments-api.com/applications/APc9vhYcPsRuTSpKD9KpMtPe"
    }
  }
}
```

### How to Create ROLE_PARTNER Credentials

The following explains how to create a new set of `ROLE_PARTNER` API credentials.

1. Login to the Finix dashboard.
2. Select the environment for which you would like to create the API credentials (Sandbox or Live).
3. In the bottom left-hand corner select the `Developer` section.
4. In the API Keys section, select `Create API Key`.

## Creating a Device Resource

Creating a device resource can be done either via the Finix dashboard or via API. Below are the steps for creating a device via API.

### Step 1: Create a Device

Create a `Device` under the `Merchant` provisioned to process In-Person Payments. Include the `Device.model` of the payment terminal you'll be using to process cards.

For more details about the payment terminals available, see our [available devices](https://docs.finix.com/guides/in-person-payments/select-your-device).

**Request**
```bash
curl -i -X POST \
  -u USfdccsr1Z5iVbXDyYt7hjZZ:313636f3-fac2-45a7-bff7-a334b93e7bda \
  https://finix.sandbox-payments-api.com/merchants/MUwfZPNW3r4EqLMzwgr6txw4/devices \
  -H 'Accept: application/hal+json' \
  -H 'Content-Type: application/json' \
  -d '{
    "description": "Cashier Three",
    "model": "PAX_D135",
    "name": "My PAX_D135 Finix Device",
    "serial_number": "19046260947"
    }
  }'
```

**Response**
```json
{
    "id": "DVxcL2fiBdt9frYCKAbZikZK",
    "created_at": "2025-05-21T19:01:32.000581Z",
    "updated_at": "2025-05-21T19:01:32.000581Z",
    "configuration_details": {
        "allow_debit": true,
        "check_for_duplicate_transactions": true,
        "prompt_amount_confirmation": true,
        "prompt_manual_entry": false,
        "signature_threshold_amount": 10000,
        "bypass_device_on_capture": true,
        "prompt_receipt_confirmation": true,
        "display_tip_on_receipt": false,
        "prompt_tip_on_screen": false,
        "allow_standalone_authorizations": false,
        "allow_standalone_sales": false,
        "allow_standalone_refunds": false,
        "tipping_details": {
            "percent_tipping_threshold": 0,
            "percent_options": [18, 20, 22],
            "fixed_options": [100, 150, 200]
        },
        "idle_message": null,
        "idle_image_file_id": null,
        "automatic_receipt_delivery_methods": null,
        "available_receipt_methods": null,
        "prompt_for_signature": "NEVER",
        "surcharge_basis_points": null
    },
    "description": "Cashier Three",
    "enabled": false,
    "idle_message": null,
    "merchant": "MU7noQ1wdgdAeAfymw2rfBMq",
    "model": "PAX_D135",
    "name": "My PAX_D135 Finix Device",
    "serial_number": "19046260947",
    "tags": {},
    "_links": {
        "self": {
            "href": "https://finix.sandbox-payments-api.com/devices/DVxcL2fiBdt9frYCKAbZikZK"
        },
        "merchant": {
            "href": "https://finix.sandbox-payments-api.com/merchants/MU7noQ1wdgdAeAfymw2rfBMq"
        },
        "transfers": {
            "href": "https://finix.sandbox-payments-api.com/transfers"
        },
        "authorizations": {
            "href": "https://finix.sandbox-payments-api.com/authorizations"
        }
    }
}
```

## Using the SDK

### Installation

Add dependency in gradle file. See [Maven Central](https://central.sonatype.com/artifact/com.finix/pax-mpos-sdk-android) or [MVN Repository](https://mvnrepository.com/artifact/com.finix/pax-mpos-sdk-android) for the latest version.

```groovy
implementation("com.finix:pax-mpos-sdk-android:3.7.0")
```

Upgrading SDK version from v2.x

SDK version 3.0.0 is a major update and is not compatible with earlier versions (2.x.x or below). If you use D135 readers in Production on SDK version 2.0.0 or above, contact Finix before updating. We will help guide the rollout and provide extra devices if needed.

### Initialization

Add permissions to AndroidManifest to interact with mPOS device via Bluetooth

```xml
<!-- For network communication -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

<!-- For bluetooth communication -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- TargetSdkVersion greater than or equal to 31 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
```

To interact with the MPOS device, it first needs to be initialized. This can be done by initializing the class `mposFinix`.

**Initialize**

```kotlin
class mposFinix(private val context: Context, private val merchantData: MerchantData)
```

- `context`: Android application context
- `merchantData`: Specific values which help identify the merchant

```kotlin
class MerchantData (
    val merchantId: String,
    val mid: String,
    val deviceId: String,
    val currency: Currency = Currency.USD,
    val env: EnvEnum = EnvEnum.SB,
    val userId: String,
    val password: String
)

val mpos = mposFinix(
    context,
    MerchantData(
        merchantId = "MUxxxxxx",
        mid = "",
        deviceId = "DVxxxxx",
        env = EnvEnum.SB,
        userId = "USxxxxxxxxx",
        password = ""
  )
)
```

Once initialized, connect to the device. When the device is ready for pairing, it will show an orange light and green light. Once connected, the orange light will disappear and only the green light will stay on.

### First Time Device Configuration

When first pairing a PAX D135 the initial configuration may take a few minutes to complete. We recommend that the user experience you build factors in the configuration time to ensure that the user knows the device configuration is in progress.

### Connect

```kotlin
fun connect(deviceName: String, deviceAddress: String, callback: MPOSConnectionCallback)
```

- `deviceName`: bluetooth name of the device
- `deviceAddress`: bluetooth address of the device
- `callback`: exposes functions which are invoked to propagate success, error, progress

**MPOSConnectionCallback**

```kotlin
interface MPOSConnectionCallback {
    fun onSuccess() // Called if the connection is successfully established
    fun onError(errorMessage: String) // Called if the connection fails for some reason
    fun onProcessing(currentStepMessage: String) // Provides status messages of what's currently happening
}
```

### Start Transaction

To start a transaction, the function `startTransaction()` must be called. This will prep the mPOS device to accept card input (swipe, tap, insert). A blue status light will be shown. Once any action is performed with the card the device would show a red light to indicate the card has been read and to remove it.

**Start Transaction**
```kotlin
fun startTransaction(
    amount: Long,
    idempotencyId: String? = null,
    transactionType: TransactionType,
    transactionCallback: MPOSTransactionCallback,
    splitTransfers: List<SplitTransfer>? = null,
    tags: Map<String, String>? = null,
    buyerIdentityId: String? = null,
    surcharge: Long? = null,
    tipAmount: Long? = null,
    promptForSignature: PromptForSignature = PromptForSignature.Never
)
```

| Field | Type | Description |
| --- | --- | --- |
| `amount` | _Long_, **required** | Amount in cents. e.g. for $10.10, this value would be 1010. |
| `idempotencyId` | _String?_, **optional** | A randomly generated or internal ID to idempotently identify Transfers, Authorizations, or refund requests. |
| `transactionType` | _TransactionType_, **required** | TransactionType enum - Sale, Refund, or Authorization. |
| `transactionCallback` | _MPOSTransactionCallback_, **required** | Callback invoked with the status of the transaction or the Transaction Result. |
| `splitTransfers` | _List<SplitTransfer>?_, **optional** | Optional list of split transfer request data. |
| `tags` | _Map<String, String>?_, **optional** | Optional map of key/value strings to be provided in the request. |
| `buyerIdentityId` | _String?_, **optional** | Optional buyer identity associated with this transaction. |
| `surcharge` | _Long?_, **optional** | Optional surcharge amount in cents. |
| `tipAmount` | _Long?_, **optional** | Optional tip amount in cents. |
| `promptForSignature` | _PromptForSignature_, **optional** | Determines whether a signature should be collected. |

**MPOSTransactionCallback**
```kotlin
interface MPOSTransactionCallback {
    fun onSuccess(result: TransactionResult?) // Called if the transaction is successfully processed
    fun onError(errorMessage: String) // Called if the transaction fails for any reason
    fun onProcessing(currentStepMessage: String) // Provides status messages of what's currently happening
}
```

## Signature Upload

When a transaction succeeds, a signature upload can be performed if `TransactionResult.signaturePending` in `MPOSTransactionCallback.onSuccess` is true. `signaturePending` is determined by the value passed with the transaction.

**Signature Upload**
```kotlin
fun uploadSignature(
    pngEncodedBase64: String,
    traceId: String,
)
```

### Referenced Refund

A referenced refund refunds the amount specified (refund amount) of a particular transaction (transaction id) to the card on file.

**Referenced Refund**
```kotlin
fun startRefund(
    idempotencyId: String? = null,
    transactionId: String,
    refundAmount: Long,
    refundCallback: MPOSRefundCallback
)
```

| Field | Type | Description |
| --- | --- | --- |
| `idempotencyId` | _String?_, **optional** | A randomly generated or internal ID to idempotently identify Transfers, Authorizations, or refund requests. |
| `transactionId` | _String_, **required** | The transaction ID correlating to a previous transaction. Returned as part of the `TransactionResult`. |
| `refundAmount` | _Long_, **required** | Amount in cents. e.g. for $10.10, this value would be 1010. |
| `refundCallback` | _MPOSRefundCallback_, **required** | Callback invoked with the status of the refund or the Refund Result. |

### Proguard Rules

If you're using proguard please add the following to your proguard rules.

```text
#Retrofit
 -dontwarn retrofit.**
 -keep class retrofit.** { *; }
 -keepattributes Signature
 -keepattributes Exceptions
 -keepattributes RuntimeVisibleAnnotations
 -keepattributes RuntimeInvisibleAnnotations
 -keepattributes RuntimeVisibleParameterAnnotations
 -keepattributes RuntimeInvisibleParameterAnnotations

#OkHttp3
 -keepattributes Signature
 -keepattributes *Annotation*
 -keep class okhttp3.** { *; }
 -keep interface okhttp3.** { *; }
 -dontwarn okhttp3.**
 -dontwarn java.nio.file.*
 -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

#Gson
  -keep class com.google.gson.stream.** { *; }

#Finix
 -dontwarn com.finix.mpos.sdk.**
 -keep class com.finix.mpos.sdk.** { *; }
 -keep class com.finix.mpos.models.** { *; }
 -keep class com.finix.common.networking.models.** { *; }
 -dontwarn java.lang.invoke.StringConcatFactory
```

### Troubleshooting with the Finix D135 Sample App

If you encounter issues with a PAX D135 while using the SDK you can reach out to the Finix Support Team at [support@finix.com](mailto:support@finix.com). Before reaching out to support, please follow the steps below to provide the necessary information to help us troubleshoot the issue.

A [sample app](https://github.com/finix-payments/finix-pax-mpos-android-sdk-demo-app) showing how to integrate the Android D135 SDK can be found here.

### Step 1: Launch the Finix D135 Sample App

### Step 2: Connect to the PAX D135

### Step 3: Click Send Debug Data
