# Querying Past Transactions

In some scenarios, your application might not receive the final transaction result from the Tap on Phone application. This can happen if your application crashes, if the Android system kills it while it runs in the background, or if the user forces the application to close. You might also need to retrieve past transaction details to populate a transaction history or details screen.

To handle these cases, you can query the status of a specific transaction by sending an Android Broadcast containing the transaction's unique ID.

## Prerequisites

Before you can query a past transaction, ensure you have:

* The `userId`, `userToken`, and `merchantId` associated with the session.  
* The `sdkTransactionId` (UUID) of the transaction you want to check. The Tap on Phone application broadcasts this ID at the very beginning of the payment process. (See [Process a Purchase Transaction](/en/get-tap-on-phone/transaction-guides/process-a-purchase-transaction) to learn how to capture this ID).

<Callout type="warning">

If you are trying to recover the status immediately after a payment attempt, wait at least **5 seconds** (ideally **10 seconds**) before sending the status request. This gives the Tap on Phone backend enough time to finish processing the transaction.

</Callout>

## Step 1: Register a Broadcast Receiver

When you query the transaction status, the Tap on Phone application responds asynchronously via a broadcast. You must register a `BroadcastReceiver` to capture this response.

By default, the Tap on Phone application responds using the `com.dejamobile.cbp.sps.TRANSACTION_STATUS_BROADCAST_RESPONSE` action.

```
val statusResponseAction = "com.dejamobile.cbp.sps.TRANSACTION_STATUS_BROADCAST_RESPONSE"

val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        // Extract the receipt or failure details
        val receipt = intent?.getStringExtra("Receipt")
        val failure = intent?.getStringExtra("Failure")

        if (receipt != null) {
            println("Got transaction receipt: $receipt")
            // Parse the receipt data to determine the final status (APPROVED/DECLINED)
        } else if (failure != null) {
            println("Transaction status failure: $failure")
            // Handle the failure
        }

        // Unregister the receiver once handled
        context?.unregisterReceiver(this)
    }
}

// Register the receiver
val filter \= IntentFilter(statusResponseAction)
registerReceiver(receiver, filter)
```

<Callout type="info">

Although the response broadcast uses the `Receipt` and `Failure` strings to bundle the outcome, the intent also carries the same detailed data fields as the standard payment intent response (such as `status`, `amount`, `pan`, etc.). See [Handle Transaction Results](/en/get-tap-on-phone/transaction-guides/handle-transaction-results) for details on parsing these fields.

</Callout>

## Step 2: Send the Status Request Broadcast

Once your receiver is listening, construct and send the broadcast intent. You must target the `TransactionStatusBroadcastReceiver` class and pass the mandatory session credentials alongside the `TransactionId`.

```
private fun queryTransactionStatus(transactionUUID: String) {
    val intent = Intent().apply {
        action = "com.dejamobile.cbp.sps.TRANSACTION_STATUS_BROADCAST"
        component = ComponentName(
            "com.dejamobile.cbp.sps.app",
            "com.dejamobile.cbp.sps.app.broadcast.TransactionStatusBroadcastReceiver"
        )
        addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)

        // Session Identifiers
        putExtra("userId", userId)
        putExtra("merchantId", merchantId)
        putExtra("userToken", userToken)

        // The UUID of the transaction to query
        putExtra("TransactionId", transactionUUID)

        // Optional: Specify your custom response action if you don't want to use the default
        // putExtra("ResponseAction", "your.custom.action.name")
    }

    // Send the broadcast
    sendBroadcast(intent)
}
```

## Step 3: Handle Errors and Retries

If your broadcast receiver catches a response that contains a `Failure` string (or if the response indicates the transaction does not exist), do not immediately assume the transaction failed permanently.

Network problems or internal device issues can occasionally cause the status retrieval to fail. Follow this retry logic:

1. **First Failure**: If the broadcast returns an error, wait a few seconds and retry the broadcast one more time.  
2. **Second Failure**: If an error is still returned after the second attempt, you can safely consider the transaction as declined or voided.