HomeGuidesReference
Log In
Guides

ForagePinPad & mPOS Integration Guide

Customize PIN entry and integrate card readers using ForageTerminalSDK

Overview

The ForagePinPad is a customizable PIN entry component that offers a secure way to collect card PINs. It features a grid of buttons (0-9) and action buttons (Delete/Clear), along with a Forage logo.

A numeric PIN pad with 12 round buttons arranged in a 4x3 grid. Buttons 1 through 9 are in green circles. The bottom row contains a gray ‘Clear’ button on the left, a green ‘0’ button in the center, and a gray backspace icon button on the right.

Styling

This section explains how to customize the full visual appearance of the ForagePinPad, including all supported styling attributes and a complete XML usage example.

Available Attributes

The ForagePinPad offers several customizable attributes to match your app’s look and feel. The table below describes each available XML attribute.

AttributeTypeDescription
forage_buttonLayoutMargindimensionMargin between buttons
forage_deleteButtonIcondrawableIcon for the delete button
forage_useDarkThemebooleanWhether to use dark theme styling
forage_useFixedAspectRatiobooleanWhether to maintain 4:3 aspect ratio for the button grid for circular or square buttons
forage_digitBackgroundColorcolorBackground color for number buttons
forage_digitFontColorcolorText color for number buttons
forage_actionBackgroundColorcolorBackground color for action buttons
forage_actionTintColorcolorTint color for action buttons
forage_digitFontSizedimensionFont size for number buttons
forage_actionFontSizedimensionFont size for action buttons
forage_borderRadiusdimensionCorner radius for all buttons
forage_clearButtonTextstringText for the clear button (defaults to "C")
forage_clearButtonOnLeftbooleanIf true the Clear button displays on the left and the Delete button should be on the right

Example Usage

Here’s a sample XML layout showing how to configure the ForagePinPad with custom styling attributes.

<com.joinforage.forage.android.pos.ui.element.ForagePinPad
    android:id="@+id/pin_pad"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:forage_buttonLayoutMargin="8dp"
    app:forage_deleteButtonIcon="<your_backspace_icon>"
    app:forage_useDarkTheme="false"
    app:forage_useFixedAspectRatio="true"
    app:forage_digitBackgroundColor="#FFFFFF"
    app:forage_digitFontColor="#000000"
    app:forage_actionBackgroundColor="#F5F5F5"
    app:forage_actionTintColor="#000000"
    app:forage_digitFontSize="24sp"
    app:forage_actionFontSize="24sp"
    app:forage_borderRadius="8dp"
    app:forage_clearButtonText="C"
    app:forage_clearButtonOnLeft="true" />

The PIN-Field UI

This section describes how to build and manage the separate PIN display UI that your app must render alongside the ForagePinPad, including event tracking and PIN state access.

📘

PIN Field Display Required

While the ForagePinPad handles secure numeric input, it does not display the entered PIN visually.

Your application is responsible for rendering a separate PIN field UI that provides visual feedback, such as masking digits with asterisks (*) or dots (), to reflect the number of digits entered.

Current PIN Length

Use the event listener and query methods below to track changes in PIN input and access the current PIN state for validation or display purposes.

To monitor the PIN length and state changes, use the setOnChangeEventListener:

pinPad.setOnChangeEventListener { state ->
    // state.length - Current number of digits entered
    // state.isEmpty - Whether no digits have been entered
    // state.isValid - Whether the current input passes validation checks
    // state.isComplete - Whether 4 digits have been entered
    // state.validationError - Any validation errors that occurred
}

To query for the current PIN length at any point, do

val currentState = pinPad.getElementState()
// Access the same properties as above:
// currentState.length
// currentState.isEmpty
// currentState.isValid
// currentState.isComplete
// currentState.validationError

Using the Moby8500 MSR via ForageTerminalSDK

This section explains how to integrate the Moby8500 card reader for magnetic stripe transactions using the ForageTerminalSDK and Ingenico’s mPOS SDK.

Add mPOS SDK Dependency

The Forage SDK includes the Ingenico mPOS SDK as a compile-time dependency only. Because it is not bundled at runtime, you must manually include the AAR file in your app’s build.gradle file:

dependencies {
   implementation files('libs/android_mPOS_sdk_3.2.0.3-release.aar')
}

👉🏻 For details on Moby-series card reader integration, see the mPOS EMV SDK documentation.

Device Setup

Before swiping a card, the Moby8500 device needs to be initialized and connected to the network. This setup process makes sure the device is ready to handle card reads using the Ingenico SDK.

Before calling .swipeMagneticCard(...), you must:

  • Initialize the Ingenico SDK
  • Connect to a PaymentDevice
  • Ensure the device is ready for card reading

Here's an example setup sequence:

// 1. Initialize Ingenico SDK
val ingenico = Ingenico.getInstance()
ingenico.initialize(
   context,
   baseUrl,
   applicationToken,
   clientVersion
)

// 2. Configure and initialize the payment device
val device = ingenico.device()
device.setDeviceType(DeviceType.MOBY8500)
device.select(
	Device(
	   DeviceType.MOBY8500,
	   CommunicationType.Usb,
	   deviceId,
	   deviceId
	)
)
device.initialize(context)

Example: MagSwipe for Balance Check

The example below demonstrates a full mag swipe and balance check flow, including SDK setup, error handling, and result parsing.

// Example exception for wrapping ForageApiResponse
class ForageApiException(val response: ForageApiResponse.Failure) : Exception(response.error.message)

// Example of performing a mag swipe and then checking balance
suspend fun performMagSwipeAndCheckBalance(
    context: Context,
    // Ingenico SDK parameters
    baseUrl: String,
    applicationToken: String,
    clientVersion: String,
    deviceId: String,
    // Forage SDK parameters
    posTerminalId: String,
    merchantId: String,
    sessionToken: String,
    // PIN entry component
    forageVaultElement: ForageVaultElement<ElementState>
): EbtBalance {

    // Initialize Ingenico SDK
    val ingenico = Ingenico.getInstance()
    ingenico.initialize(
        context,
        baseUrl,
        applicationToken,
        clientVersion
    )

    // Configure and initialize the payment device
    val device = ingenico.device()
    device.setDeviceType(DeviceType.MOBY8500)
    device.select(
        Device(
            DeviceType.MOBY8500,
            CommunicationType.Usb,
            deviceId,
            deviceId
        )
    )
    device.initialize(context)

    // Initialize ForageTerminalSDK
    val forageTerminalSdk = ForageTerminalSDK.init(
        context = context,
        posTerminalId = posTerminalId,
        forageConfig = ForageConfig(
            merchantId = merchantId,
            sessionToken = sessionToken
        )
    )

    // Perform the mag swipe
    val swipeResponse = forageTerminalSdk.swipeMagneticCard(device)

    if (swipeResponse is ForageApiResponse.Failure) {
        throw ForageApiException(swipeResponse)
    }

    // At this point we know swipeResponse is Success
    val magSwipeInteraction = (swipeResponse as ForageApiResponse.Success<MagSwipeInteraction>).data

    // Use the mag swipe data to check balance
    val balanceResponse = forageTerminalSdk.checkBalance(
        CheckBalanceParams(
            forageVaultElement = forageVaultElement,
            interaction = magSwipeInteraction
        )
    )

    if (balanceResponse is ForageApiResponse.Failure) {
        throw ForageApiException(balanceResponse)
    }

    // At this point we know balanceResponse is Success
    return (balanceResponse as ForageApiResponse.Success<String>).toBalance() as EbtBalance
}