Introduction
The Halo UI SDK provides a ready-made, Jetpack Compose-based interface for integrating Halo payment services into your Android application. It handles the transaction flow, card reading animations, result screens and receipt delivery, so you can focus on your core business logic.
🚀 Features​
- Ready-to-use UI: Fullscreen transaction flow including amount entry, card-reading animations, and success/failure screens.
- Full screen or bottom sheet: Present each charge as its own screen, or as a sheet over your app — chosen per transaction. See Presentation.
- Theming: Light mode, dark mode, custom colors, shapes, type sizes, and company logo.
- Simple API: Initialize and launch a transaction with suspend functions —
initwaits for the SDK's real bring-up outcome,launchreturns the transaction result. - Digital receipts: The cardholder's receipt is sent by the Halo kernel to an email address or mobile number the merchant enters — see Receipts.
- Inbound payment links: App-to-app intents, custom-scheme URLs and your own App Link domain are handled natively by the SDK, with no host code — see Inbound Payments.
- DebiCheck mandates: A TT3 debit-order mandate arrives through the same doors as a payment and runs the same tap flow, with the order's terms on the screen the payer taps against — see DebiCheck Mandates.
- Push to Terminal: A payment sent straight to a named device — no QR to scan — with no manifest changes on your side. See Push to Terminal.
- Localization: Built-in translations for English, Afrikaans, Zulu, French, German, Spanish, and Portuguese — follows the device language by default.
- Cross-runtime friendly: Compose-free theme builders and a suspending token callback make the SDK straightforward to embed from a Flutter or React Native host.
Dynamic Currency Conversion (DCC) is implemented but not yet exposed — the showDCC option is commented out in HDConfig while the flow is reworked. See DCC.
📋 Prerequisites​
Before you begin, ensure your project meets the following requirements:
- Android 10.0 (API level 29) or higher.
- Halo SDK Credentials: A valid SDK token provided by Synthesis/Halo.
- A
ComponentActivity(or subclass such asAppCompatActivity) to host the SDK.
The activity passed to HDConfig must be a ComponentActivity (or a subclass such as AppCompatActivity or FlutterFragmentActivity), since the SDK renders its UI with Jetpack Compose.
The Four Calls​
The host's entire view of the SDK is four calls, each made at the earliest moment it is possible to make it:
| Call | When | Needs |
|---|---|---|
HaloSdkUi.attach(activity, savedInstanceState) | First line of onCreate, after super.onCreate | Nothing but the activity |
HaloSdkUi.prepare(config) | At your splash screen | Your HDConfig |
HaloSdkUi.init(config) | As soon as you have a session token | A session token |
HaloSdkUi.launch(...) | Per charge | — |
The ordering is deliberate: each call needs strictly more than the one before it, so the bring-up cost spreads across your startup instead of piling up in front of a merchant holding a card. Skipping any of the first three is legal and costs only speed — the next call does that work as well. The SDK logs a warning if attach runs late.
attach also wires the Android lifecycle through to the SDK, so you do not forward onStart, onResume, onPause or onStop yourself.
init is where the device registers: it re-attests only when the token's identity has changed since last time, and the runtime permissions in Permissions are requested alongside it rather than before it — a denial doesn't block bring-up. See Configuration for the full detail on each call.
Example Activity Declaration​
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import za.co.synthesis.halo.sdk_ui.HaloSdkUi
import za.co.synthesis.halo.sdk_ui.models.HDConfig
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 1. Hand the SDK its context — the most expensive step, so it goes first.
HaloSdkUi.attach(this, savedInstanceState)
// One config, used by both prepare and init.
val config = HDConfig(
activity = this,
onTokenRequest = { fetchTokenFromBackend() },
)
// 2. Cache branding and warm the artwork. No token needed, returns at once.
HaloSdkUi.prepare(config)
// 3. Register the device and bring the SDK up.
lifecycleScope.launch {
val result = HaloSdkUi.init(config)
// result?.resultType / result?.errorCode carry why, if bring-up failed.
}
// ... set your own content
}
}
prepare and init must be given the same configuration. prepare caches the branding an inbound payment paints itself with, and init registers against it — different values mean a payment arriving cold looks like a different app.