Process a Purchase Transaction
This guide explains how to initiate a standard purchase transaction using the Tap on Phone application. You use an Android Intent to launch the payment interface, pass the transaction details (such as the amount and currency), and handle the response when the payment completes.
Prerequisites
Before you process a purchase, ensure you have:
- Successfully initialized the Tap on Phone application. (See Initializing the POS or verify using Checking POS Status).
- The
userId,userToken, andmerchantIdassociated with the current session. - Implemented the AndroidX Activity Result APIs in your project.
Step 1: Register the Activity Result Launcher
When the payment finishes, the Tap on Phone application returns control to your application via an Activity Result. You must register a callback to handle this outcome.
val paymentResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val data = result.data
if (result.resultCode == Activity.RESULT_OK && data != null) {
// The transaction process completed and generated a receipt.
val status = data.getStringExtra("status") ?: "None"
if (status == "APPROVED") {
println("Payment approved successfully!")
// Extract receipt data and display success to the merchant
} else {
val declineCause = data.getStringExtra("declineCause") ?: "Unknown"
println("Payment declined: $declineCause")
// Display decline reason to the merchant
}
} else if (result.resultCode == Activity.RESULT_CANCELED) {
// The user canceled the payment, or a pre-transaction error occurred.
val errorCode = data?.getStringExtra("errorCode") ?: "None"
val errorMessage = data?.getStringExtra("errorMessage") ?: "User Canceled"
println("Payment canceled or failed: $errorMessage ($errorCode)")
}
}A RESULT_OK response means the process finished, but it does not guarantee the payment was approved. Always evaluate the status string inside the returned intent data.
Step 2: Listen for the Transaction ID (Recommended)
As soon as the Tap on Phone application begins processing the payment intent, it broadcasts a unique sdkTransactionId. If your application crashes or misses the final Activity Result, you need this ID to recover the transaction status.
Register a broadcast receiver before launching the payment intent:
val transactionIdReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val transactionId = intent?.getStringExtra("sdkTransactionId")
println("Transaction started with ID: $transactionId")
// Save this ID temporarily in case you need to recover the transaction
}
}
// Register the receiver
ContextCompat.registerReceiver(
requireActivity(), // or 'this' if in an Activity
transactionIdReceiver,
IntentFilter("com.dejamobile.cbp.sps.TRANSACTION_BROADCAST_RESPONSE"),
ContextCompat.RECEIVER_EXPORTED
)The Tap on Phone app might emit this broadcast multiple times per intent call if an error occurs early and a new transaction ID is generated.
Step 3: Construct and Launch the Payment Intent
Create an explicit intent targeting the Tap on Phone application’s POSActivity. You must include the transaction details as extras.
Pay special attention to the amount:
- Amount: You must provide the total amount in cents (for example,
$12.00is1200). This value represents the total transaction amount, including any tips. - Tip: If you provide a tip amount, you must also provide it in cents. This is strictly metadata. The Tap on Phone application does not add the tip to the
amountfield automatically.
private fun performPurchase(amountInCents: Long, tipInCents: Long? = null) {
// 1. Calculate the final total amount
var finalAmount = amountInCents
if (tipInCents != null) {
finalAmount += tipInCents
}
// 2. Build the intent
val intent = Intent().apply {
setClassName(
"com.dejamobile.cbp.sps.app",
"com.dejamobile.cbp.sps.app.POSActivity"
)
// Session Identifiers
putExtra("userId", userId)
putExtra("userToken", userToken)
putExtra("merchantId", merchantId)
// Transaction Details
putExtra("transactionType", "PURCHASE")
putExtra("amount", finalAmount)
if (tipInCents != null) {
putExtra("tip", tipInCents)
}
// Optional Configuration
putExtra("paymentMode", "Card") // Default is "Card". "Link" is also supported.
putExtra("externalTransactionReference", "ORDER-12345") // Link this payment to your internal order ID
putExtra("locale", "en_US") // Force a specific language on the payment screen
putExtra("transitionAuto", true) // Automatically transition back to your app after completion
}
// 3. Launch the intent
paymentResultLauncher.launch(intent)
}Step 4: Handle the Result
When you launch the intent, the Tap on Phone application takes over the screen, prompts the user to tap a card or device, and processes the payment with the acquiring network.
Once finished, the Tap on Phone interface closes, and your paymentResultLauncher receives the result. Extract the receipt data to format a customer receipt or record the transaction in your backend.
- Remember to unregister your
transactionIdReceiverafter the payment concludes to prevent memory leaks.
Next Steps
- Learn how to extract and format the full receipt data in Handle Transaction Results.
- Understand how to process cancellations and refunds in Process a Refund or Cancellation.