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.

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.
Attribute | Type | Description |
---|---|---|
forage_buttonLayoutMargin | dimension | Margin between buttons |
forage_deleteButtonIcon | drawable | Icon for the delete button |
forage_useDarkTheme | boolean | Whether to use dark theme styling |
forage_useFixedAspectRatio | boolean | Whether to maintain 4:3 aspect ratio for the button grid for circular or square buttons |
forage_digitBackgroundColor | color | Background color for number buttons |
forage_digitFontColor | color | Text color for number buttons |
forage_actionBackgroundColor | color | Background color for action buttons |
forage_actionTintColor | color | Tint color for action buttons |
forage_digitFontSize | dimension | Font size for number buttons |
forage_actionFontSize | dimension | Font size for action buttons |
forage_borderRadius | dimension | Corner radius for all buttons |
forage_clearButtonText | string | Text for the clear button (defaults to "C") |
forage_clearButtonOnLeft | boolean | If 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
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
}
Updated about 17 hours ago