Extract the transaction reference from the WebView callback URL. Send it to your backend verify endpoint using Retrofit (or OkHttp) with Kotlin coroutines. Your backend calls the Paystack verify API and returns the result. Update your Android UI based on the verified flag and amount returned.
// viewmodel/PaymentViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
sealed class VerifyState {
object Loading : VerifyState()
data class Success(val amount: Double, val currency: String, val reference: String) : VerifyState()
data class Failure(val message: String) : VerifyState()
}
class PaymentViewModel : ViewModel() {
private val _verifyState = MutableStateFlow<VerifyState>(VerifyState.Loading)
val verifyState: StateFlow<VerifyState> = _verifyState
fun verifyPayment(reference: String) {
viewModelScope.launch {
_verifyState.value = VerifyState.Loading
try {
val result = RetrofitClient.paymentApi.verify(reference)
if (result.verified) {
_verifyState.value = VerifyState.Success(
amount = result.amount ?: 0.0,
currency = result.currency ?: "NGN",
reference = result.reference ?: reference
)
} else {
_verifyState.value = VerifyState.Failure("Payment not confirmed")
}
} catch (e: Exception) {
_verifyState.value = VerifyState.Failure(
e.message ?: "Network error. Check your connection."
)
}
}
}
}
// PaymentResultActivity.kt
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class PaymentResultActivity : AppCompatActivity() {
private val viewModel: PaymentViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_payment_result)
val reference = intent.getStringExtra("reference") ?: return finish()
val progressBar = findViewById<ProgressBar>(R.id.progressBar)
val statusText = findViewById<TextView>(R.id.statusText)
val retryButton = findViewById<Button>(R.id.retryButton)
retryButton.setOnClickListener { viewModel.verifyPayment(reference) }
lifecycleScope.launch {
viewModel.verifyState.collect { state ->
when (state) {
is VerifyState.Loading -> {
progressBar.visibility = View.VISIBLE
statusText.text = "Verifying payment..."
retryButton.visibility = View.GONE
}
is VerifyState.Success -> {
progressBar.visibility = View.GONE
statusText.text = "Payment confirmed!
${state.currency} ${state.amount}"
retryButton.visibility = View.GONE
}
is VerifyState.Failure -> {
progressBar.visibility = View.GONE
statusText.text = state.message
retryButton.visibility = View.VISIBLE
}
}
}
}
viewModel.verifyPayment(reference)
}
}
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
This guide is part of the Paystack integration guides by language and framework series.
KES 2,999
The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.
Start Paystack Course