Android SDK (PAX) — Integration Guide
Fetch the integration-path skill for machine-readable setup guidance and code examples: /.well-known/skills/paths/android-pax.md
Need the terminal to also accept transactions triggered by a back-office server or a separate POS? See Android SDK (PAX) — Cloud API Integrated Mode.
What is this integration path?
The Android SDK (PAX) path runs your application directly on the PAX SmartPOS terminal. The Handpoint Android SDK communicates with the Handpoint Payments App on the same device via IPC — no external server or network hop is required for the payment flow.
Choose this path when your POS UI, checkout logic, and payment terminal are all the same device. It gives you complete control of the on-terminal experience with the simplest possible integration surface.
When to use it
| ✅ Good fit | ❌ Not a good fit |
|---|---|
| Your Android app runs on PAX hardware and owns the full checkout UX | Your POS runs on a separate server — use the Cloud REST API |
| You want to minimise network dependencies in the payment path | You need a Bluetooth card reader — use the Android HiLite path |
| You're targeting PAX A920, A920 Pro, A77, or similar SmartPOS devices | You need iOS support — use the iOS HiLite path |
Backoffice REST API operations — tip adjustment, reversals, refunds, MOTO charges, batch management, deferred tokenization — are available alongside any integration path you choose. They go server-side directly to the payment gateway with no terminal or SDK required. Subject only to acquirer support.
How it works
Your Android Activity
│ hapi.sale() / hapi.refund() …
▼
Handpoint Android SDK
│ IPC — same device
▼
Handpoint Payments App (PAX)
│ chip / tap / swipe + P2PE
▼
Acquirer / Card Network
│
▼
endOfTransaction(TransactionResult)
- Your app calls an SDK method (e.g.
hapi.sale()). - The SDK passes the command to the Handpoint Payments App on the same device via IPC.
- The Payments App reads the card, encrypts, and processes with the acquirer.
- The result is delivered to your
endOfTransactioncallback.
Your app never handles raw card data — Handpoint keeps you out of PCI scope.
Authentication
| Credential | Purpose | Provisioned by |
|---|---|---|
sharedSecret | Authenticates your app to the Payments App on the terminal | Handpoint Integration Support |
cloudApiKey | Optional. Required for keyed entry operations, SDK-initiated transaction recovery (getTransactionStatus()), and cloud channel (integrated mode). Not required for card-present operations. | Handpoint Integration Support |
The sharedSecret is a 64-character hex string unique to the merchant. The cloudApiKey is not required for standard card-present integrations.
Environments & credentials
| Terminal type | Notes |
|---|---|
| PAX debug terminal | Development — uses cloud.handpoint.io for Cloud features |
| PAX production terminal (DEMO merchant) | Simulated acquirer — funds not moved |
| PAX production terminal (live merchant) | Real transactions — live merchant credentials |
See Development hardware to identify your terminal type. Debug and production credentials are not interchangeable.
Setup
1. Request credentials
Contact your Handpoint Integration Support engineer for:
- Merchant
sharedSecret - DEMO merchant
cloudApiKey - A PAX DEMO or debug terminal
2. Add the SDK dependency
// build.gradle (app module)
dependencies {
implementation 'com.handpoint.api:sdk:7.x.x' // latest: see release notes
}
// Top-level build.gradle
allprojects {
repositories {
google()
mavenCentral()
}
}
RC (debug terminal) builds require the Handpoint Nexus server — contact Integration Support for credentials.
Required build.gradle settings:
android {
defaultConfig {
minSdkVersion 22
multiDexEnabled true
ndk {
abiFilters "armeabi-v7a"
}
}
// AGP 7 / 8
packaging {
jniLibs { pickFirsts += ['**/*.so'] }
}
}
If using AndroidX, add to gradle.properties:
android.useAndroidX=true
android.enableJetifier=true
3. Update AndroidManifest.xml
<application
android:extractNativeLibs="true"
...>
<activity
android:launchMode="singleTask"
...>
4. Implement the Events interface and initialise
class MainActivity : AppCompatActivity(), Events.SmartposRequired {
private lateinit var hapi: Hapi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val credentials = HandpointCredentials(
sharedSecret = "0102030405060708091011121314151617181920212223242526272829303132",
cloudApiKey = "YOUR_CLOUD_API_KEY" // omit if not using recovery
)
hapi = HapiFactory.getAsyncInterface(this, this, credentials, Settings())
}
// Fires when any operation completes
override fun endOfTransaction(result: TransactionResult, device: Device) { }
// SDK status — InitialisationComplete fires here
override fun currentTransactionStatus(statusInfo: StatusInfo, device: Device) {
if (statusInfo.status == StatusInfo.Status.InitialisationComplete) {
// Safe to start financial operations now
}
}
override fun connectionStatusChanged(status: ConnectionStatus, device: Device) { }
// Fires when getTransactionStatus returns a result
override fun transactionResultReady(result: TransactionResult, device: Device) { }
}
Do not call hapi.sale() or any financial operation until currentTransactionStatus fires with InitialisationComplete. Calling before initialisation results in CommandNotAllowed or NotInitialised.