---
title: Transactions
slug: LEHl-transactions
docTags: 
createdAt: 2024-11-27T11:53:45.337Z
---

## States

These are the possible states when processing a [purchase](docId\:xfTYvCsCNePqsmJfZ6o4a) or [refund](docId\:ezdh0uhDPD1bvbGCddqiO):

```kotlin
enum class TransactionState {
    /**
     * Transaction is idle and ready to start
     */
    READY,

    /**
     * Attempting connection to the [ToroClient.selectedDevice]
     */
    CONNECTING_TO_DEVICE,

    /**
     * Awaiting confirmation of gratuity amount from the customer
     * Only applicable if [ToroConfig.gratuityEnabled] is true
     */
    AWAITING_GRATUITY,

    /**
     * Awaiting customer to present card on any interface (contact, contactless, magswipe).
     */
    AWAITING_CARD,

    /**
     * Awaiting customer signature (in app or on device).
     * @see ToroConfig.signatureMode
     */
    AWAITING_SIGNATURE,

    /**
     * Awaiting customer to enter PIN on the device.
     */
    AWAITING_PIN_ENTRY,

    /**
     * Awaiting customer to select application on the device.
     */
    AWAITING_APPLICATION_SELECTION,

    /**
     * Contacting the gateway to authorise the transaction.
     */
    AUTHORISING,

    /**
     * Transaction was completed successfully and an
     * outcome was received (approved, declined etc.)
     */
    COMPLETED,

    /**
     * Transaction was cancelled by the user or operator
     */
    CANCELLED,

    /**
     * Transaction failed due to an error
     */
    FAILED
}
```

### Transaction State Listener

To receive transaction state updates, you can implement the `TransactionStateListener` and register it with the `ToroClient` instance:

:::CodeblockTabs
```kotlin
val transactionStateListener = TransactionStateListener { newState ->
    // Handle transaction state updates here
}

// Register the listener with the ToroClient instance
toro.setTransactionStateListener(transactionStateListener)
```

```java
TransactionStateListener listener = state -> {
    // Handle transaction state updates here
};

toro.setTransactionStateListener(listener);
```
:::

Alternatively, you can use the `transactionState` property on the `ToroClient` instance to check the current state of the transaction:

:::CodeblockTabs
```kotlin
val transactionState = toro.transactionState
```

```java
TransactionState state = toro.getTransactionState();
```
:::

This will return the current transaction state as a `TransactionState` enum value.

## Metadata

The `TransactionMetadata` class allows you to include additional information with [purchases](docId\:xfTYvCsCNePqsmJfZ6o4a) and [refunds](docId\:ezdh0uhDPD1bvbGCddqiO).

```kotlin
/***
 * Optional metadata for the transaction
 */
data class TransactionMetadata(

    /**
     * Custom ID for the transaction. This saleReferenceId will be returned in the [TransactionReceipt].
     * Max length is 35 characters.
     */
    val saleReferenceId: String? = null,

    /**
     * The gratuity amount for the transaction.
     * The gratuity amount is added to the transaction amount specified in startTransaction().
     * This is useful if you are wanting to use a custom gratuity flow outside of the SDK.
     */
    val gratuityAmount: Int = 0,

    /**
     * Details of the original transaction that is being refunded, cancelled or completed.
     * Not applicable for purchases.
     */
    val originalTransactionDetails: OriginalTransactionDetails? = null,

    /**
     * Any other additional data you want returned in the [TransactionReceipt]
     * This data will be sent in the `AcceptorAuthorisationRequest` - AccptrAuthstnReq/AuthstnReq/Tx/TxDtls/AddtlInf
     */
    val additionalInformation: Map<String, Any?> = emptyMap()
)
```

## Cancelling an in-progress transaction

To cancel an in-progress [purchase](docId\:xfTYvCsCNePqsmJfZ6o4a) or [refund](docId\:ezdh0uhDPD1bvbGCddqiO), you can call the `cancelTransaction` method on the `ToroClient` instance:

:::CodeblockTabs
```kotlin
toro.cancelTransaction()
```

```java
toro.cancelTransaction();
```
:::

This will also close the USB/Bluetooth session with the Miura device if it is open.

## Card events

Possible events and their descriptions are below:

```kotlin
enum class CardEvent {
    /**
     * Card inserted into the chip reader
     */
    CardInserted,

    /**
     * Card removed from the chip reader
     */
    CardRemoved,

    /**
     * Card swiped on magnetic stripe reader
     */
    CardSwiped,

    /**
     * Represent the card on any interface
     */
    TryCardAgain,

    /**
     * Represent the card using either chip or magnetic stripe reader
     */
    InsertOrSwipeCard,

    /**
     * Represent the card using chip reader
     */
    InsertCard;
}
```

### Card Event Listener

The SDK will notify you of card events using the `CardEventListener` interface. You can register a `CardEventListener` with the `ToroClient` instance like so:

:::CodeblockTabs
```kotlin
val cardEventListener = CardEventListener { event ->
    // Handle card events here
}

// Register the listener with the ToroClient instance
toro.setCardEventListener(cardEventListener)
```

```java
CardEventListener cardEventListener = event -> {
    // Handle card events here
};

// Register the listener with the ToroClient instance
toro.setCardEventListener(cardEventListener);
```
:::

## Signatures

The SDK provides two different methods for collecting cardholder signatures. The method used depends on the `signatureMode` set in the `ToroConfig`. See [configuration](docId:59sfhN6-ZRIn1pEwwtMz8) for more information.

**`SignatureMode.DEVICE`**

The signature will be captured on the Miura device. This is only applicable to devices which have a touch screen (e.g., M021). No additional configuration is required for this mode to work.

**`SignatureMode.APP`**

The signature will be captured in the app. This can be used for all devices, and requires some setup for it to work. This setup can be seen in the `TransactionProcessingFragment` in the sample application.

:::CodeblockTabs
```kotlin
@AndroidEntryPoint
class TransactionProcessingFragment : Fragment() {
    private var _binding: FragmentTransactionProcessingBinding? = null
    private val binding get() = _binding!!

    @Inject
    lateinit var toro: ToroClient

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentTransactionProcessingBinding.inflate(inflater, container, false)

        handleSignature()
        return binding.root
    }

    private fun handleSignature() {
      // Register for the signature activity result
      val launcher = registerForActivityResult(
          ActivityResultContracts.StartActivityForResult(),
          toro.signatureActivityResultCallback
      )

      // Pass the launcher to the ToroClient instance so it can
      // process the result
      toro.setSignatureLauncher(launcher)
  }
}
```

```java
@AndroidEntryPoint
public class TransactionProcessingFragment extends Fragment {
    private FragmentTransactionProcessingBinding binding;
    
    @Inject
    ToroClient toro;

    @Override
    public View onCreateView(
            LayoutInflater inflater, 
            ViewGroup container,
            Bundle savedInstanceState
    ) {
        binding = FragmentTransactionProcessingBinding.inflate(inflater, container, false);
        handleSignature();
        return binding.getRoot();
    }

    private void handleSignature() {
        // Register for the signature activity result
        ActivityResultLauncher<Intent> launcher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            toro.getSignatureActivityResultCallback()
        );

        // Pass the launcher to the ToroClient instance so it can
        // process the result
        toro.setSignatureLauncher(launcher);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}
```
:::

In your app, you should call `toro.setSignatureLauncher(launcher)` in the activity/fragment where the transaction will be in a `AWAITING_SIGNATURE` state.

The SDK will then automatically launch the `SignatureActivity` when required. The activity is shown below.

::Image[]{src="https://api.archbee.com/api/optimize/NWfX_cs_B_73KTvNy1ETb/MCnfBJxvtGxD-2vBG6iqM_toro-signature-activity-filled.png" size="50" width="1080" height="2340" position="center" caption="Built-in SignatureActivity" alt="Built-in SignatureActivity" darkWidth="1080" darkHeight="2340" showCaption="true"}

## Receipt

Below is the `TransactionReceipt` object you will receive in the `onCompleted` callback when calling `startTransaction()` for a  [purchase](docId\:xfTYvCsCNePqsmJfZ6o4a) or [refund](docId\:ezdh0uhDPD1bvbGCddqiO).

```kotlin
data class TransactionReceipt(
    /**
     *  Unique reference number to identify the transaction.
     *  Can be set in [TransactionMetadata].
     */
    val saleReferenceId: String? = null,

    /**
     * The total amount of the transaction represented in the smallest
     * unit of the currency, e.g. cents for USD, pence for GBP.
     */
    val amount: Int,

    /**
     * The amount of the transaction that was authorised by the acquirer.
     * In most cases the same as [amount], but can differ e.g. partial approvals.
     */
    val authorisedAmount: Int? = null,

    /**
     * The type of transaction. Purchase, refund.
     * @see TransactionType
     */
    val type: TransactionType,

    /**
     * Gratuity amount confirmed by the customer.
     * This can be set either through [TransactionMetadata] or
     * when [ToroConfig.gratuityEnabled] is set to true and the built in
     * gratuity flow is used.
     */
    val gratuityAmount: Int,

    /**
     * The currency of the transaction.
     */
    val currency: CurrencyCode,

    /**
     * The authorisation code set by the acquirer.
     */
    val authCode: String? = null,

    /**
     * The result of the authorisation (acquirer decision).
     * Typically APPROVED or DECLINED.
     */
    val responseCode: ResponseCode,

    /**
     * The reason for the [ResponseCode].
     */
    val responseReason: String? = null,

    /**
     * Cardholder Verification Method
     */
    val authenticationMethod: AuthenticationMethod8? = null,

    /**
     * Additional response information (from gateway or acquirer).
     */
    val additionalResponseInformation: String? = null,

    /**
     * Also known as the authorisation response code.
     * EMV tag 8A set by the acquirer.
     */
    val actionCode: String? = null,

    /**
     * Application identifier of the card that was presented
     */
    val aid: String? = null,

    /**
     * Application label of the card that was presented
     */
    val applicationLabel: String? = null,

    /**
     * The payment interface used to process the transaction.
     * E.g. Contactless.
     */
    val paymentInterface: PaymentInterface,

    /**
     * The first 6 or 8 digits of the Primary Account Number (PAN).
     * AKA Bank Identification Number (BIN).
     */
    val panStart: String?,

    /**
     * The last 4 digits of the Primary Account Number (PAN).
     */
    val panLastFour: String?,

    /**
     * Identifier set by the recipient (acquirer) to reference the transaction.
     * This can be the same as the [initiatorTransactionId] depending on the acquirer.
     */
    val recipientTransactionId: String?,

    /**
     * Identifier set by the initiator (merchant) to reference the transaction.
     * The Toro SDK handles this internally and cannot be overridden by the host application.
     */
    val initiatorTransactionId: String?,

    /**
     * Unique identification of the transaction assigned by the POI (Point Of Interaction)
     */
    val transactionReference: String?,

    /**
     * The date and time the transaction occurred in ISO 8601 format.
     */
    val dateTime: String?,

    /**
     * The serial number of the terminal the transaction was processed on.
     */
    val terminalSerialNumber: String,

    /**
     * Cardholder signature base64 encoded if applicable.
     */
    val signatureBase64: String? = null,

    /**
     * Indicates whether the signature verification failed, either due to
     * merchant rejection or customer cancellation during signature entry.
     * The host application should send cancellation advice in this case.
     */
    val signatureVerificationFailed: Boolean = false,

    /**
     * Whether the transaction was captured by the acquirer.
     */
    val captured: Boolean,

    /**
     * The latitude of the device at the point of transaction.
     */
    val longitude: String? = null,

    /**
     * The longitude of the device at the point of transaction.
     */
    val latitude: String? = null,
    
    /**
     * The custom data set in [TransactionMetadata]
     */
    val additionalInformation: Map<String, Any?>? = null
)
```

##

