SDK Lifecycle and Deinitialization
deinit() ends the SDK's current setup so your app can initialize it again without restarting. Use it when replacing the API key, changing environments, switching to a different merchant on the device, or testing a complete reset. These examples require Android SDK 1.0.7 or later and apply to UAT and Production.
Choose the right cleanup operation
| Operation | What it does | What you do next |
|---|---|---|
logout() |
Clears the merchant session and active location; preserves SDK initialization and device enrollment | Log in again and select a location |
unenrollDevice() |
Attempts Visa unenrollment and clears local enrollment certificates, keys, device identifiers, and enrollment state; keeps the SDK initialized | Enroll again before accepting taps |
deinit() |
Unenrolls, logs out, releases the reader service, clears the SDK's API key, and removes the SDK instance | Initialize again, log in, select a location, and enroll |
Use logout() for an ordinary sign-out when the device will continue with the same merchant. Use deinit() for a complete reset. For canceling a tap or releasing only the reader connection, see Running Payments.
What deinit does
The SDK runs these cleanup steps in order:
- Calls
unenrollDevice()before logging out. It attempts to unenroll with Visa and clears local enrollment state, including device keys, certificates, the Visa device ID, and saved enrollment details. Local enrollment state is cleared even if Visa unenrollment fails. - Calls
logout()to clear the merchant session and active location. - Resets the connection to the Visa reader service.
- Clears the API-key provider and saved key fingerprint, removes the singleton instance, and cancels its internal coroutine scope.
Cleanup is best effort: a Visa unenrollment failure does not prevent the remaining cleanup. A completed local reset is not confirmation that remote unenrollment succeeded. Deinitialization does not revoke your API key, delete the merchant or transaction records in Koard, or uninstall Visa Tap to Pay Ready.
Check initialization state
import com.koardlabs.merchant.sdk.KoardMerchantSdk
val sdkInitialized = KoardMerchantSdk.isInitialized()
This static check is safe before initialization and from any thread. It returns false before initialize() and after deinit() completes. getInstance() throws when no instance exists.
Initialization only means an SDK instance exists. It does not prove the merchant is authenticated, enrolled, or ready to accept a payment. While initialized, observe sdk.readinessState and require isReadyForTransactions before starting a tap.
Deinitialize and initialize again
Call both lifecycle operations on a worker thread. The helpers below switch to Dispatchers.IO:
import android.app.Application
import com.koardlabs.merchant.sdk.KoardMerchantSdk
import com.koardlabs.merchant.sdk.domain.KoardEnvironment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
suspend fun deinitializeSdk() = withContext(Dispatchers.IO) {
if (KoardMerchantSdk.isInitialized()) {
KoardMerchantSdk.getInstance().deinit()
}
check(!KoardMerchantSdk.isInitialized())
}
suspend fun initializeSdk(
application: Application,
apiKey: String,
environment: KoardEnvironment
) = withContext(Dispatchers.IO) {
if (!KoardMerchantSdk.isInitialized()) {
KoardMerchantSdk.initialize(
application = application,
apiKey = apiKey,
environment = environment
)
}
}
Use KoardEnvironment.UAT with your UAT key or KoardEnvironment.PROD with your production key. Your app supplies the key again; the deinitialized SDK cannot recover it for you. Keep it in your app's existing credential/configuration mechanism and never print it in logs.
Run deinitialization after payment and reader work has finished. Use an application/service coroutine scope that remains alive during cleanup, and await completion before offering Initialize or launching another SDK operation. The initialization flag is a snapshot, not a lock or a stream of cleanup progress; keep a separate UI busy state while deinitializing.
After initialization, obtain a new KoardMerchantSdk.getInstance(). Discard references to the old SDK and subscribe to the new instance's readiness state. Then log in, choose the active location, and enroll and check readiness again before accepting taps. Android deinit clears enrollment, so initialization alone cannot restore payment readiness.
Verify the flow in the demo
In the internal Android demo with lifecycle controls:
- Open Settings → Deinitialize SDK after completing any payment.
- Wait for cleanup. The app returns to Login and shows the SDK as not initialized.
- Tap Initialize SDK. The demo reuses its build configuration's API key and enables merchant sign-in.
- Log in, select a location, and enroll again. Confirm payment readiness separately from initialization.
The demo retains its own test configuration; this does not mean the SDK retains the key after deinit. The same flow works in the UAT and Production builds with the corresponding configuration.
See also
- Transaction Metadata
- Running Payments
- iOS SDK Lifecycle — iOS preserves device enrollment during deinit

