> For the complete documentation index, see [llms.txt](https://docs.verifone.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.verifone.com/psdk-latest/psdk-user-guide-and-training/psdk-user-guide/pay_at_table.md).

# Pay at Table

In a full-service restaurant environment, it is common for the customer to pay their experience at the table, interacting directly with a hand-held POI. This flow illustrates how this might be accomplished from the POS. In this diagram, the Cashier is the person that provides the POI to the Customer.

## Pay at Table with Card <a href="#id2" id="id2"></a>

{% @plantuml/diagram content="        @startuml
hide footbox

```
    participant POS order 10
    participant POI order 20
    actor Cashier order 30
    actor Customer order 40
    |||
    POS <-> POS : **1** Initialize with listening enabled
    ...
    POS <- Cashier : Cashier adds items for a specific\ntable/Customer over time
    ...
    POI <- Cashier : Cashier wakes POI
    POS <<- POI : POI connects to the POS and POS\nreceives notification that the POI is available

    POS ->> POI : **2** Request Cashier ID
    POI <-> Cashier : Cashier inputs their ID\nor selects their name from a list
    POS <<- POI : **2** Receive a UserInputEvent\ncontaining the ID information
    POS <<->> POI : **3** Login on behalf of the current Cashier

    == Process Orders ==
    POS ->> POI : **4** Request the table/order
    POI <-> Cashier : Cashier inputs table/order or selects it from a list
    POS <<- POI : **4** Receive a UserInputEvent\ncontaining the table/order information
    POS <<->> POI : **5** Start a session for the current order
    POS <<->> POI : **6** Load the items from the current order\nas merchandise in the basket

    POS ->> POI : **7** Request the Cashier to confirm the order\nand to provide the POI to the Customer
    note over POS, POI : If desired, also request to split the check
    POI <-> Cashier : Cashier confirms
    POS <<- POI : **7** Receive a UserInputEvent with the confirmation

    POS ->> POI : **8a** Start the payment
    Cashier -> Customer : Cashier hands the device to the Customer
    POI <-> Customer : Prompts the Customer\nto confirm the amount / basket
    POI <-> Customer : Prompts the Customer\nto present their payment instrument
    ... POI handles remaining interaction\nand host authorization ...
    POS <<- POI : **8a** Receive a PaymentCompletedEvent

    POS ->> POI : **9** Request receipt delivery method
    POI <-> Customer : Customer selects Print
    POS <<- POI : **9** Receive a UserInputEvent with the selection
    POS <-> POI : **10a** Request the receipt to be printed
    POI -> POI : Print receipt with built-in printer

    POS <<->> POI : **11** POS ends the session
    Cashier <- Customer : Cashier receives the POI from the Customer
    POS ->> POI : **12** Request the Cashier to confirm\nif there are additional orders to process
    alt Cashier confirms
      POI <-> Cashier : Cashier confirms
      POS <<- POI : **12** Receive UserInputEvent with confirmed true
      POS -> POS : Go to 4
    else Cashier cancels
      POI <-> Cashier : Cashier cancels
      POS <<- POI : **12** Receive UserInputEvent with confirmed false
      POS -> POS : Go to 13
    end

    == Finished Processing Orders ==
    POS <<->> POI : **13** POS logs out
    ...
    POS <<- POI : POI notifies POS that it is disconnecting
    POI -> POI : POI sleeps
    |||
    @enduml" %}
```

## Pay at Table with Cash <a href="#id3" id="id3"></a>

{% @plantuml/diagram content="        @startuml
hide footbox

```
    participant POS order 10
    participant POI order 20
    actor Cashier order 30
    actor Customer order 40
    |||
    
    ... See Pay at Table with Card until starting payment ...
    POS ->> POI : **8b** Start the payment
    Cashier -> Customer : Cashier hands the device to the Customer
    POI <-> Customer : Prompts the Customer\nto confirm the amount / basket
    POI <-> Customer : Prompts the Customer\nto present their payment instrument
    POI <- Customer : Customer selects Cash
    POS <<- POI : **8b** Receive a PaymentCompletedEvent with Cash

    POS ->> POI : **9** Request receipt delivery method
    POI <-> Customer : Customer selects Print
    POS <<- POI : **9** Receive a UserInputEvent with the selection

    POS ->> POI : **10b** Request confirmation from the Customer\nto return the POI
    POI -> Customer : Displays prompt to the Customer
    Cashier <- Customer : Cashier receives the POI from the Customer
    POI <- Cashier : Confirms the device is returned
    POS <<- POI : **10b** Receive a UserInputEvent with the selection
    POS ->> POI : **10c** Request confirmation from the Cashier\nthat the cash is received
    POI <-> Cashier : Cashier confirms cash received
    POS <<- POI : **10c** Receive a UserInputEvent with the confirmation
    POS -> POS : Holds order until Cashier\nputs cash in drawer and gets change
    POS <<->> POI : **11** POS ends the session

    ... Process more orders per flow in Pay at Table with Card ...

    POS <<->> POI : **13** POS logs out
    ...
    POS <<- POI : POI notifies POS that it is disconnecting
    POI -> POI : POI sleeps
    ...
    POS <- Cashier : Cashier accesses order and handles cash completion
    POS -> POS : Prints receipt per customer request
    Cashier -> Customer : Cashier provides Customer with receipt
    |||
    @enduml" %}
```

## Code Examples <a href="#code-examples" id="code-examples"></a>

### 1: Initialize with Listening <a href="#initialize-with-listening" id="initialize-with-listening"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
import com.verifone.payment_sdk.*;

private PaymentSdk mPaymentSdk;

private final CommerceListenerAdapter mCommerceListenerAdapter = new CommerceListenerAdapter() {
    @Override
    public void handleStatus(Status status) {
        if (status.getStatus() == StatusCode.SUCCESS) {
            // Now you can get the transaction manager and log in.
        } else {
            // Initialization failed, look at the status code and message to determine why.
        }
    }
};

private void psdkInit() {
    new AsyncTask<Context, Void, Void>(){
        @Override
        protected Void doInBackground(Context... contexts) {
            // Create PaymentSdk
            mPaymentSdk = PaymentSdk.create(contexts[0]);
            HashMap<String, String> paramMap = new HashMap<>();

            // Enable listening
            paramMap.put(TransactionManager.DEVICE_LISTEN_KEY, TransactionManager.ENABLED_VALUE);
            paramMap.put(PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY, "tcpip");
            paramMap.put(PsdkDeviceInformation.DEVICE_SERIAL_NUMBER_KEY, PsdkDeviceInformation.ACCEPT_ANY_DEVICE_VALUE);
            mPaymentSdk.initializeFromValues(mCommerceListenerAdapter, paramMap);
        }
    }.execute(someContext);
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 import com.verifone.payment_sdk.*

private val mPaymentSdk: PaymentSdk

private val mCommerceListenerAdapter = object : CommerceListenerAdapter() {
    override fun handleStatus(status: Status) {
        if (status.getStatus() === StatusCode.SUCCESS) {
            // Now you can get the transaction manager and log in.
        } else {
            // Initialization failed, look at the status code and message to determine why.
        }
    }
}

suspend fun psdkInit(context: Context) {
    // Create PaymentSdk
    mPaymentSdk = PaymentSdk.create(context)

    // Enable listening
    val paramMap: HashMap<String, String> = hashMapOf(
        TransactionManager.DEVICE_LISTEN_KEY to TransactionManager.ENABLED_VALUE,
        PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY to "tcpip",
        PsdkDeviceInformation.DEVICE_SERIAL_NUMBER_KEY to PsdkDeviceInformation.ACCEPT_ANY_DEVICE_VALUE
    )

    mPaymentSdk.initializeFromValues(mCommerceListenerAdapter, paramMap)
}

private fun getStarted() {
    val job = Job()
    val scope = CoroutineScope(Dispatchers.IO + job)
    scope.launch {
        // first connection
        psdkInit(false, false, context)
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// Overridden from the VFICommerceListenerAdapter
override func handle(_ status: VFIStatus?) {
    if (VFIStatusCodeSuccess == status?.getStatus()) {
        // Now you can get the transaction manager and log in.
    } else {
        // Initialization failed, look at the status code and message to determine why.
    }
}

func psdkInit() {
    // Create PaymentSdk
    let sdk = VFIPaymentSdk.createPaymentSdk()
    let adapter = CommerceListenerAdapter(listener: self)

    // Enable listening
    let connectConfig = [
        // Enable listening
        VFITransactionManagerDEVICELISTENKEY: VFITransactionManagerENABLEDVALUE,
        VFIPsdkDeviceInformationDEVICECONNECTIONTYPEKEY: "tcpip",
        VFIPsdkDeviceInformationDEVICESERIALNUMBERKEY: VFIPsdkDeviceInformationACCEPTANYDEVICEVALUE]
    sdk.initialize(fromValues: adapter, config: connectConfig)
}
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> using PaymentSDK;
</strong>using PaymentSdkUi;

private readonly PaymentSdk payment_sdk_;
private readonly TransactionManager transaction_manager;

// EventHandler
sdk_payment_event_handler_ = async (sender, args) =>
{
    if (args.Status == StatusCode.SUCCESS)
    {
        payment_sdk_.TransactionManager.HandleBasketEvent += basket_event_handler_;
        // Subscribe to other events
        // Now you can log in.
    }
    else
    {
        // Initialization failed, look at the status code and message to determine why.
    }
};

void PsdkInit()
{
    // Create PaymentSdk
    payment_sdk_ = new PaymentSdk();

    // Enable listening
    var param_map = new Windows.Foundation.Collections.StringMap
    {
        {TransactionManager.DEVICE_LISTEN_KEY, TransactionManager.ENABLED_VALUE},
        {PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY, "tcpip"},
        {PsdkDeviceInformation.DEVICE_SERIAL_NUMBER_KEY, PsdkDeviceInformation.ACCEPT_ANY_DEVICE_VALUE}
    };
    payment_sdk_.InitializeFromValues(param_map);
}
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
class CommerceAdapter : public verifone_sdk::CommerceListenerAdapter {
 public:
  ~CommerceAdapter() override = default;

  void handleStatus(const std::shared_ptr<verifone_sdk::Status>& status) override {
    if (status->getStatus() == verifone_sdk::StatusCode::SUCCESS) {
      // Now you can get the transaction manager and log in.
    } else {
      // Initialization failed, look at the status code and message to determine why.
    }
  }
};

void psdkInit(bool use_last_device) {
  // Create PaymentSdk
  payment_sdk_ = verifone_sdk::PaymentSdkInterface::create(
      verifone_sdk::CreatePlatformContextLinux(std::nullopt));
  auto adapter_ = std::make_shared<CommerceAdapter>();

  // Specify the connection type and address
  std::unordered_map<std::string, std::string> param_map{
      {verifone_sdk::TransactonManager::DEVICE_LISTEN_KEY,
       verifone_sdk::TransactionManager::ENABLED_VALUE},
      {verifone_sdk::PsdkDeviceInformation::DEVICE_CONNECTION_TYPE_KEY, "tcpip"},
      {verifone_sdk::PsdkDeviceInformation::DEVICE_SERIAL_NUMBER_KEY,
       verifone_sdk::PsdkDeviceInformation::ACCEPT_ANY_DEVICE_VALUE}};
  payment_sdk_->initializeFromValues(adapter_, param_map);
}
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
 using PaymentSDK;

private readonly PaymentSdk payment_sdk_;

// EventHandler
public void HandleStatus(Status status) {
    if (status.StatusCode == 0)
    {
        // Subscribe to other events
        // Now you can log in.
    }
    else
    {
        // Initialization failed, look at the status code and message to determine why.
    }
};

void PsdkInit()
{
    // Create PaymentSdk
    payment_sdk_ = new PaymentSdk();

    // Enable listening
    var param_map = new Dictionary<string, string>
    {
        {TransactionManager.DEVICE_LISTEN_KEY, TransactionManager.ENABLED_VALUE},
        {PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY, "tcpip"},
        {PsdkDeviceInformation.DEVICE_SERIAL_NUMBER_KEY, PsdkDeviceInformation.ACCEPT_ANY_DEVICE_VALUE}
    };
    payment_sdk_.InitializeFromValues(param_map);
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 2, 4, 7, 10b, 10c, 12: Request Confirmation <a href="#b-10c-12-request-confirmation" id="b-10c-12-request-confirmation"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
@Override // Overridden from the CommerceListenerAdapter
public void handleUserInputEvent(UserInputEvent event) {
    if (UserInputEvent.RECEIVED_TYPE.equals(event.getType())) {
        Values receivedValues = event.getValues();
        if (event.getInputType() == InputType.CONFIRMATION) {
            if (receivedValues.isConfirmed()) {
                // Received confirmation.
            } else {
                // User canceled.
            }
        }
    }
}

// A default value is not applicable for confirmations.
mTransactionManager.requestUserInput(InputType.CONFIRMATION, "Message to display", null);
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 // Overridden from the CommerceListenerAdapter
override fun handleUserInputEvent(event: UserInputEvent) {
    if (UserInputEvent.RECEIVED_TYPE.equals(event.getType())) {
        val receivedValues = event.getValues()
        if (event.getInputType() == InputType.CONFIRMATION) {
            if (receivedValues.isConfirmed()) {
                // Received confirmation.
            } else {
                // User canceled.
            }
        }
    }
}

// A default value is not applicable for confirmations.
mTransactionManager.requestUserInput(InputType.CONFIRMATION, "Message to display", null)
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code overflow="wrap" lineNumbers="true" %}

```swift
// Overridden from the VFICommerceListenerAdapter
override func handle(_ event: VFIUserInputEvent?) {
    if (VFIUserInputEventRECEIVEDTYPE == event?.getType()) {
        if (VFIInputType.CONFIRMATION == event?.getInputType()) {
            if let receivedValues: VFIValues = event?.getValues() {
                if receivedValues.isConfirmed() {
                    // Received confirmation.
                } else {
                    // User canceled.
                }
            }
        }
    }
}

// A default value is not applicable for confirmations.
sdk.getTransactionManager()?.requestUserInput(VFIInputType.CONFIRMATION, message: "Message to display", defaultValue: "Default value")
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> private readonly EventHandler&#x3C;UserInputEvent> user_input_event_handler_;
</strong>
private void HandleEvent(UserInputEvent event)
{
    if (event.Type == UserInputEvent.RECEIVED_TYPE)
    {
        Values received_values = event.ResponseValues;
        if (event.InputType == InputType.CONFIRMATION)
        {
            if (received_values.Confirmed)
            {
                // Received confirmation.
            }
            else
            {
                // User canceled.
            }
        }
    }
}

// ...
// Link event handler after initialization is complete but before requesting input
user_input_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};
payment_sdk_.TransactionManager.HandleUserInputEvent += user_input_event_handler_;

// ...
// Request confirmation. A default value is not applicable for confirmations.
payment_sdk_.TransactionManager.RequestUserInput(InputType.CONFIRMATION, "Message to display", NULL);
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
// Overridden from the CommerceListenerAdapter
void handleUserInputEvent (
        const std::shared_ptr<verifone_sdk::UserInputEvent>& event) override {
    if (event->getType() == verifone_sdk::UserInputEvent::RECEIVED_TYPE
        && event->getInputType() == verifone_sdk::InputType::CONFIRMATION) {
      if (event->getValues()->isConfirmed()) {
        // Received confirmation.
      } else {
        // User canceled.
      }
    }
  }
// ...

// A default value is not applicable for confirmations.
auto status = psdk->getTransactionManager()->requestUserInput(
    InputType::CONFIRMATION, "Message to display", "");
if (status->getStatus() == verifone_sdk::StatusCode::SUCCESS) {
  //operation initiated successfully
}
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code overflow="wrap" lineNumbers="true" %}

```aspnet
public void HandleUserInputEvent(UserInputEvent sdk_event)
{
    if (sdk_event.Type == UserInputEvent.RECEIVED_TYPE)
    {
        Values received_values = sdk_event.Values;
        if (sdk_event.InputType == VerifoneSdk.InputType.CONFIRMATION)
        {
            if (received_values.IsConfirmed)
            {
                // Received confirmation.
            }
            else
            {
                // User canceled.
            }
        }
    }
}

// ...
// Request confirmation. A default value is not applicable for confirmations.
payment_sdk_.TransactionManager.RequestUserInput(InputType.CONFIRMATION, "Message to display", NULL);
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 3: Login <a href="#login" id="login"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
private final CommerceListenerAdapter mCommerceListenerAdapter = new CommerceListenerAdapter() {
    @Override
    public void handleTransactionEvent(TransactionEvent event) {
        if (TransactionEvent.LOGIN_COMPLETED.equals(event.getType())) {
          if (event.getStatus() == StatusCode.SUCCESS) {
              // Login is complete.
          } else {
              // Handle failure by examining the status code and message.
          }
        }
    }
}

// ...
// The PaymentSdk must be initialized to login and the CommerceListenerAdapter
// should be provided in the initialize APIs.

// Username, password, shift ID and Merchant ID are optional. Providing the username
// links any following transactions to that user/cashier and can be
// useful for reporting.
LoginCredentials credentials = LoginCredentials.createWith2("username", null, null, null);
mPaymentSdk.getTransactionManager().loginWithCredentials(credentials);
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 private val mCommerceListenerAdapter = object : CommerceListenerAdapter() {
    override fun handleTransactionEvent(event: TransactionEvent) {
        if (TransactionEvent.LOGIN_COMPLETED.equals(event.getType())) {
            if (event.getStatus() == StatusCode.SUCCESS) {
                // Login is complete.
            } else {
                // Handle failure by examining the status code and message.
            }
        }
    }
}

suspend fun psdkTransactionManagerLogin()
{
    // Username, password, shift ID and Merchant ID are optional. Providing the username
    // links any following transactions to that user/cashier and can be
    // useful for reporting.
    val credentials =
    LoginCredentials.createWith2("username", null, null, null)
    mPaymentSdk.getTransactionManager()!!.loginWithCredentials(credentials)
}

// ...
// The PaymentSdk must be initialized to login and the CommerceListenerAdapter
// should be provided in the initialize APIs.

// Perform the login using a co-routine.
val job = Job()
val scope = CoroutineScope(Dispatchers.IO + job)
scope.launch {
    psdkTransactionManagerLogin()
}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// Overridden from the VFICommerceListenerAdapter
override func handle(_ event: VFITransactionEvent?) {
    if (VFITransactionEventLOGINCOMPLETED == event?.getType()) {
        if (VFIStatusCodeSuccess == event?.getStatus()) {
            // Login is complete.
        } else {
            // Handle failure by examining the status code and message.
        }
    }
}

let adapter = VFICommerceListenerAdapter()

// ...
// The PaymentSdk must be initialized to login and the VFICommerceListenerAdapter
// should be provided in the initialize APIs.

// Username, password, shift ID and Merchant ID are optional. Providing the username
// links any following transactions to that user/cashier and can be
// useful for reporting.
let loginCredentials = VFILoginCredentials.createWith2("user", password: nil, shiftNumber: nil, merchantId: nil)
let result = sdk.getTransactionManager()?.login(with: loginCredentials)
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> private readonly EventHandler&#x3C;TransactionEvent> transaction_event_handler_;
</strong>
private void HandleEvent(TransactionEvent event)
{
    if (event.Type.Value == TransactionEvent.LOGIN_COMPLETED)
    {
        if (event.Status == 0)
        {
            // Login is complete.
        }
        else
        {
            // Handle failure by examining the status code and message.
        }
    }
}

// ...
// Link event handler after initialization is complete
transaction_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};
payment_sdk_.HandleTransactionEvent += transaction_event_handler_;

// Username, password, and shift ID are optional. Providing the username
// links any following transactions to that user/cashier and can be
// useful for reporting.
var credentials = new LoginCredentials();
credentials.UserId = "username";
var result = payment_sdk_.TransactionManager.LoginWithCredentials(credentials);
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
class CommerceAdapter: public verifone_sdk::CommerceListenerAdapter {
 public:
  void handleTransactionEvent(
      const std::shared_ptr<verifone_sdk::TransactionEvent>& event) override {
    if (event->getType() == verifone_sdk::TransactionEvent::LOGIN_COMPLETED) {
      if (event->getStatus() == verifone_sdk::StatusCode::SUCCESS) {
        // Login is complete.
      } else {
        // Handle failure by examining the status code and message.
      }
    }
  }
  // ...
}

// ...
// The PaymentSdk must be initialized to login and the CommerceListenerAdapter
// should be provided in the initialize APIs.

if (auto transaction_manager = psdk->getTransactionManager()) {
  // Username, password, shift ID and Merchant ID are optional. Providing the username
  // links any following transactions to that user/cashier and can be
  // useful for reporting.
  auto credentials = verifone_sdk::LoginCredentials::createWith2("user", null, null, null);
  auto status = transaction_manager_->loginWithCredentials(credentials);
}
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
public void HandleTransactionEvent(TransactionEvent sdk_event)
{
    if (sdk_event.Type == TransactionEvent.LOGIN_COMPLETED)
    {
        if (sdk_event.Status == 0)
        {
            // Login is complete.
        }
        else
        {
            // Handle failure by examining the status code and message.
        }
    }
}

// Username, password, and shift ID are optional. Providing the username
// links any following transactions to that user/cashier and can be
// useful for reporting.
var credentials = LoginCredentials.Create();
credentials.UserId = "username";
credentials.Password = "password";
credentials.ShiftNumber = "shift";
var result = payment_sdk_.TransactionManager.LoginWithCredentials(credentials);
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 5: Start Session <a href="#start-session" id="start-session"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
private final CommerceListenerAdapter mCommerceListenerAdapter = new CommerceListenerAdapter() {
    @Override
    public void handleTransactionEvent(TransactionEvent event) {
        if (CommerceEvent.SESSION_STARTED.equals(event.getType())) {
          if (event.getStatus() == StatusCode.SUCCESS) {
              // Session is started
          } else {
              // Handle failure by examining the status code and message.
          }
        }
    }
    // ...
}

// ...
// Must be logged in to start a session

// Using the same listener for initialize.
// The transaction can also be modified before sending to configure the currency,
// change the shift ID or cashier ID, and configure manual prompt options to be
// used as the default for any following payments.
if (transactionManager.startSession2(Transaction.create())) {
    // Session start was sent successfully
} else {
    // Session start failed to send
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 private val mCommerceListenerAdapter = object : CommerceListenerAdapter() {
    override fun handleTransactionEvent(event: TransactionEvent) {
        if (TransactionEvent.SESSION_STARTED.equals(event.getType())) {
            if (event.getStatus() == StatusCode.SUCCESS) {
                // Session is started
            } else {
                // Handle failure by examining the status code and message.
            }
        }
    }
}

let adapter = CommerceListenerAdapter()

suspend fun psdkTransactionManagerStartSession()
{
    // Using the same listener for initialize.
    // The transaction can also be modified before sending to configure the currency,
    // change the shift ID or cashier ID, and configure manual prompt options to be
    // used as the default for any following payments.
    if (mPaymentSdk.getTransactionManager()!!.startSession2(Transaction.create())) {
        // Session start was sent successfully
    } else {
        // Session start failed to send
    }
}

// ...
// Must be logged in to start a session

// Perform the login using a co-routine.
val job = Job()
val scope = CoroutineScope(Dispatchers.IO + job)
scope.launch {
    psdkTransactionManagerStartSession()
}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// Overridden from the VFICommerceListenerAdapter
override func handle(_ event: VFITransactionEvent?) {
    if (VFICommerceEventSESSIONSTARTED == event?.getType()) {
        if (VFIStatusCodeSuccess == event?.getStatus()) {
            // Session is started
        } else {
            // Handle failure by examining the status code and message.
        }
    }
}

let adapter = CommerceListenerAdapter(listener: self)

// ...
// Must be logged in to start a session

// Using the same listener for initialize.
// The transaction can also be modified before sending to configure the currency,
// change the shift ID or cashier ID, and configure manual prompt options to be
// used as the default for any following payments.
let status = sdk.getTransactionManager()?.startSession2(VFITransaction.create()) ?? false
if status {
    // Session start was sent successfully
} else {
    // Session start failed to send
}
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> private readonly EventHandler&#x3C;TransactionEvent> transaction_event_handler_;
</strong>
private void HandleEvent(TransactionEvent event)
{
    if (event.Type == TransactionEvent.SESSION_STARTED)
    {
        if (event.Status == StatusCode.SUCCESS)
        {
            // Session is started
        }
        else
        {
            // Handle failure by examining the status code and message.
        }
    }
}

// ...
// Link event handler after initialization is complete
transaction_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};
// It's possible to use the same transaction_event_handler_ from Login if desired.
payment_sdk_.HandleTransactionEvent += transaction_event_handler_;

// ...
// Must be logged in to start a session

// The transaction can also be modified before sending to configure the currency,
// change the shift ID or cashier ID, and configure manual prompt options to be
// used as the default for any following payments.
if (payment_sdk_.TransactionManager.StartSession2(new Transaction()))
{
    // Session start was sent successfully
}
else
{
    // Session start failed to send
}
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
class CommerceAdapter: public verifone_sdk::CommerceListenerAdapter {
 public:
  void handleTransactionEvent(const std::shared_ptr<verifone_sdk::TransactionEvent>& event)
      override {
    if (event->getType() == verifone_sdk::TransactionEvent::SESSION_STARTED) {
      if (event->getStatus() == verifone_sdk::StatusCode::SUCCESS) {
        // Session is started
      } else {
        // Handle failure by examining the status code and message.
      }
    }
  }
  // ...
}

// ...
// Must be logged in to start a session

// The same listener from initialize can be used.
// The transaction can also be modified before sending to configure the currency,
// change the shift ID or cashier ID, and configure manual prompt options to be
// used as the default for any following payments.
auto transaction_manager = psdk->getTransactionManager();
if (transaction_manager &&
    transaction_manager->startSession2(verifone_sdk::Transaction::create())) {
  // Session start was sent successfully
} else {
  // Session start failed to send
}
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
private readonly EventHandler<TransactionEvent> transaction_event_handler_;
public void HandleTransactionEvent(TransactionEvent sdk_event)
{
    if (sdk_event.Type == CommerceEvent.SESSION_STARTED)
        {
            if (sdk_event.Status == 0)
            {
                // Session is started
            }
            else
            {
                // Handle failure by examining the status code and message.
            }
        }
}


// ...
// Must be logged in to start a session

// The transaction can also be modified before sending to configure the currency,
// change the shift ID or cashier ID, and configure manual prompt options to be
// used as the default for any following payments.
if (payment_sdk_.TransactionManager.StartSession(new Transaction()))
{
    // Session start was sent successfully
}
else
{
    // Session start failed to send
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 6: Restore Basket <a href="#restore-basket" id="restore-basket"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
// A session must be open to display basket items

// This uses a basket object that has already been created,
// simply restoring it to the screen. This also uses an amount totals
// object that already contains the correct totals for this order.
transactionManager.getBasketManager().registerBasket(storedBasket, storedAmountTotals);
// Listener receives the BasketEvent
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 // A session must be open to display basket items

// This uses a basket object that has already been created,
// simply restoring it to the screen. This also uses an amount totals
// object that already contains the correct totals for this order.
transactionManager.getBasketManager().registerBasket(storedBasket, storedAmountTotals)
// Listener receives the BasketEvent
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// A session must be open to display basket items

// This uses a basket object that has already been created,
// simply restoring it to the screen. This also uses an amount totals
// object that already contains the correct totals for this order.
transactionManager?.getBasketManager()?.register(storedBasket, totals: storedAmountTotals)
// Listener receives the BasketEvent
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> // A session must be open to display basket items
</strong>
// This uses a basket object that has already been created,
// simply restoring it to the screen. This also uses an amount totals
// object that already contains the correct totals for this order.
transactionManager.BasketManager.RegisterBasket(storedBasket, storedAmountTotals);
// Listener receives the BasketEvent
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
// A session must be open to display basket items

// This uses a basket object that has already been created,
// simply restoring it to the screen. This also uses an amount totals
// object that already contains the correct totals for this order.
transaction_manager->getBasketManager()->registerBasket(storedBasket, storedAmountTotals);
// Listener receives the BasketEvent
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
// A session must be open to display basket items

// This uses a basket object that has already been created,
// simply restoring it to the screen. This also uses an amount totals
// object that already contains the correct totals for this order.
TransactionManager.BasketManager.RegisterBasket(storedBasket, storedAmountTotals);
// Listener receives the BasketEvent
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**Todo:** Add a see-also section referencing how to add items to a basket, and create a new section for storing a basket for later.
{% endhint %}

### 8a: Start Normal Payment <a href="#a-start-normal-payment" id="a-start-normal-payment"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
// A session must be open to perform a payment

Payment payment = Payment.create();
// Creating a Payment also creates an empty AmountTotals object in the requested amounts.
AmountTotals requestedAmounts = payment.getRequestedAmounts();
// Please note that all amount fields are optional and
// should be omitted or set to null if not used.
requestedAmounts.setSubtotal(
ConversionUtility.parseAmount(8.00));
requestedAmounts.setTax(ConversionUtility.parseAmount(1.00));
requestedAmounts.setGratuity(ConversionUtility.parseAmount(1.00));
requestedAmounts.setTotal(ConversionUtility.parseAmount(10.00));
transactionManager.startPayment(payment);
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 // A session must be open to perform a payment
// Please note that all amount fields are optional and
// should be omitted or set to null if not used.
 val payment = Payment.create().apply {
    RequestedAmounts.apply {
        Subtotal = Decimal(8.00)
        Tax = Decimal(1.00)
        Gratuity = Decimal(1.00)
        Total = Decimal(10.00)
    }
}
// Creating a Payment also creates an empty AmountTotals object in the requested amounts.
transactionManager.startPayment(payment)
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// A session must be open to perform a payment

var payment = VFIPayment.create()
// Creating a Payment also creates an empty AmountTotals object in the requested amounts.
// Please note that all amount fields are optional and
// should be omitted or set to null if not used.
var requestedAmounts = payment?.getRequestedAmounts()
requestedAmounts?.setSubtotal(VFIDecimal.init(valueDecimal: Decimal.init(8.00)))
requestedAmounts?.setTax(VFIDecimal.init(valueDecimal: Decimal.init(1.00)))
requestedAmounts?.setGratuity(VFIDecimal.init(valueDecimal: Decimal.init(1.00)))
requestedAmounts?.setTotal(VFIDecimal.init(valueDecimal: Decimal.init(10.00)))
sdk.getTransactionManager()?.start(payment)
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> // A session must be open to perform a payment
</strong>
// Please note that all amount fields are optional and
// should be omitted or set to null if not used.
var amount_totals = new AmountTotals();
PaymentSDK.Decimal subtotal = new PaymentSDK.Decimal(8.00);
PaymentSDK.Decimal gratuity = new PaymentSDK.Decimal(1.00);
PaymentSDK.Decimal tax = new PaymentSDK.Decimal(1.00);
PaymentSDK.Decimal total = new PaymentSDK.Decimal(10.00);
amount_totals.SetWithAmounts(subtotal, tax, gratuity, total);
var payment = new Payment
{
    RequestedAmounts = amount_totals
};
payment_sdk_.TransactionManager.StartPayment(payment);
// Listener receives the PaymentCompletedEvent.
</code></pre>

{% endtab %}

{% tab title="Lineos" %}
{% code lineNumbers="true" %}

```cpp
   // A session must be open to perform a payment

   auto payment = verifone_sdk::Payment::create();
   // Creating a Payment also creates an empty AmountTotals object in the requested amounts.
   // Please note that all amount fields are optional and
   // should be omitted or set to null if not used.
   payment->getRequestedAmounts()->setSubTotals(8.00)
                                 ->setTax(1.00)
                                 ->setGratuity(1.00)
                                 ->setTotal(10.00);
   psdk->getTransactionManager()->startPayment(payment);
   // Listener receives the PaymentCompletedEvent.


.. code-tab:: c# .NET
   :linenos:

   // A session must be open to perform a payment
   // Please note that all amount fields are optional and
   // should be omitted or set to null if not used.

   var amount_totals = AmountTotals.Create(false);
   VerifoneSdk.Decimal subtotal = new VerifoneSdk.Decimal(8);
   VerifoneSdk.Decimal gratuity = new VerifoneSdk.Decimal(1);
   VerifoneSdk.Decimal tax = new VerifoneSdk.Decimal(1);
   VerifoneSdk.Decimal total = new VerifoneSdk.Decimal(10);
   amount_totals.SetWithAmounts(subtotal, tax, gratuity, total, null, null, null);
   var payment = Payment.Create();
   payment.RequestedAmounts = amount_totals;
   payment_sdk_.TransactionManager.StartPayment(payment);
   // Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 8b: Start Cash Payment <a href="#b-start-cash-payment" id="b-start-cash-payment"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
// A session must be open to perform a payment

// Create the payment and set the payment type to cash
Payment payment = Payment.create();
payment.setRequestedPaymentType(PaymentType.CASH);
// Configure amounts and other payment properties before starting.
transactionManager.startPayment(payment);
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 // A session must be open to perform a payment

// Create the payment and set the payment type to cash
val payment = Payment.create()
payment.setRequestedPaymentType(PaymentType.CASH)
// Configure amounts and other payment properties before starting.
transactionManager.startPayment(payment)
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// A session must be open to perform a payment

// Create the payment and set the payment type to cash
var payment = VFIPayment.create()
payment?.setRequestedPaymentType(paymentType: VFIPaymentType.CASH)
// Configure amounts and other payment properties before starting.
sdk.getTransactionManager()?.start(payment)
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong>// A session must be open to perform a payment
</strong><strong> 
</strong>// Create the payment and set the payment type to cash
Payment payment = new Payment();
payment.RequestedPaymentType(PaymentType.CASH);
// Configure amounts and other payment properties before starting.
payment_sdk_.TransactionManager.StartPayment(payment);
// Listener receives the PaymentCompletedEvent.
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
// A session must be open to perform a payment

// Create the payment and set the payment type to cash
auto payment = Payment::create();
payment->setRequestedPaymentType(PaymentType::CASH);
// Configure amounts and other payment properties before starting.
psdk->getTransactionManager()->startPayment(payment);
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
// A session must be open to perform a payment

// Create the payment and set the payment type to cash
Payment payment = Payment.Create();
ayment.RequestedPaymentType = PaymentType.CASH;
// Configure amounts and other payment properties before starting.
payment_sdk_.TransactionManager.StartPayment(payment);
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 9: Request Receipt Delivery Method <a href="#request-receipt-delivery-method" id="request-receipt-delivery-method"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
@Override // Overridden from the CommerceListenerAdapter
public void handleUserInputEvent(UserInputEvent event) {
    if (UserInputEvent.RECEIVED_TYPE.equals(event.getType())) {
        Values valueFromCustomer = event.getValues();
        if (event.getInputType() == InputType.MENU_OPTIONS) {
            if (event.getStatus() == StatusCode.SUCCESS) {
                int selectedIndex = valueFromCustomer.getSelectedIndices()[0];
                // Use selected index to determine which button they selected.
                // In this example, index 0 is Print, 1 is Email, etc.
            } // else handle error
        } // else handle other input response
    } // else handle input request from POI
    return null;
}

final String header = "How would you like your receipt?";
final String[] buttons = new String[] {
        "Print",
        "Email",
        "SMS",
        "None"
};
mTransactionManager.presentUserOptions(header, buttons);
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 // Overridden from the CommerceListenerAdapter
override fun handleUserInputEvent(event: UserInputEvent) {
    if (UserInputEvent.RECEIVED_TYPE.equals(event.getType())) {
        val valueFromCustomer = event.getValues()
        if (event.getInputType() == InputType.MENU_OPTIONS) {
            if (event.getStatus() == StatusCode.SUCCESS) {
                val selectedIndex = valueFromCustomer.getSelectedIndices()[0]
                // Use selected index to determine which button they selected.
                // In this example, index 0 is Print, 1 is Email, etc.
            } // else handle error
        } // else handle other input response
    } // else handle input request from POI
}

val header = "How would you like your receipt?"
val buttons = arrayOf("Print", "Email", "SMS", "None")
mTransactionManager.presentUserOptions(header, buttons)
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// Overridden from the VFICommerceListenerAdapter
override func handle(_ event: VFIUserInputEvent?) {
    if (VFIUserInputEventRECEIVEDTYPE == event?.getType()) {
        var valueFromCustomer = event?.getValues()
        if (VFIInputType.MENUOPTIONS == event?.getInputType()) {
                if (VFIStatusCodeSuccess == event?.getStatus()) {
                    var selectedIndex = valueFromCustomer?.getSelectedIndices()[0]
                    // Use selected index to determine which button they selected.
                    // In this example, index 0 is Print, 1 is Email, etc.
                } // else handle error
            } // else handle other input response
        } // else handle input request from POI
}

let header = "How would you like your receipt?"
let buttons = ["Print", "Email", "SMS", "None"]
sdk.getTransactionManager()?.presentUserOptions(header, buttonLabels: buttons)
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> private readonly EventHandler&#x3C;UserInputEvent> user_input_event_handler_;
</strong>
private void HandleEvent(UserInputEvent event)
{
    if (event.Type == UserInputEvent.RECEIVED_TYPE)
    {
        Values value_from_customer = event.ResponseValues;
        if (event.InputType == InputType.MENU_OPTIONS)
        {
            if (event.Status == StatusCode.SUCCESS)
            {
                int selected_index = value_from_customer.SelectedIndices[0];
                // Use selected index to determine which button they selected.
                // In this example, index 0 is Print, 1 is Email, etc.
            } // else handle error
        } // else handle other input response
    } // else handle input request from POI
}

// ...
// Link event handler after initialization is complete but before requesting input
user_input_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};
payment_sdk_.TransactionManager.HandleUserInputEvent += user_input_event_handler_;

// ...
// Present the tip options.
string header = "How would you like your receipt?";
string[] buttons = new string[] {"Print", "Email", "SMS", "None"};
payment_sdk_.TransactionManager.PresentUserOptions(header, buttons);
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
// Overridden from the CommerceListenerAdapter
void handleUserInputEvent (
    const std::shared_ptr<verifone_sdk::UserInputEvent>& event) override {
    if (event->getType() == verifone_sdk::UserInputEvent::RECEIVED_TYPE) {
      auto values = event->getValues();
      if (event->getInputType() == InputType::MENU_OPTIONS) {
        if (event->getStatus() == StatusCode::SUCCESS) {
          auto selected_indices = event->getValues()->getSelectedIndices();
          // Use selected indices to determine which button they selected.
          // In this example, index 0 is Print, 1 is Email, etc.
        } // else handle error
      } // else handle other input response
    } // else handle input request from POI
}
// ...

std::vector<std::string> options = {"Print", "Email", "SMS", "None"};
auto status = psdk->getTransactionManager()->presentUserOptions(
    "How would you like your receipt?", options);
if (status->getStatus() == verifone_sdk::StatusCode::SUCCESS) {
  //operation initiated successfully
}
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
public void HandleUserInputEvent(UserInputEvent sdk_event)
{
    if (sdk_event.Type == UserInputEvent.RECEIVED_TYPE)
    {
        Values value_from_customer = sdk_event.Values;
        if (sdk_event.InputType == VerifoneSdk.InputType.MENU_OPTIONS)
        {
            if (sdk_event.Status == 0)
            {
                int selected_index = value_from_customer.SelectedIndices[0];
                // Use selected index to determine which button they selected.
                // In this example, index 0 is Print, 1 is Email, etc.
            } // else handle error
        } // else handle other input response
    } // else handle input request from POI
}

// ...
// Present the tip options.
string header = "How would you like your receipt?";
string[] buttons = new string[] {"Print", "Email", "SMS", "None"};
payment_sdk_.TransactionManager.PresentUserOptions(header, buttons);
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 10a: Request the Receipt to be Printed <a href="#a-request-the-receipt-to-be-printed" id="a-request-the-receipt-to-be-printed"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
@Override // Overridden from the CommerceListenerAdapter
public void handlePrintEvent(PrintEvent event) {
    if (PrintEvent.REQUEST_TYPE.equals(event.getType())) {
        if (event.getStatus() == StatusCode.SUCCESS) {
            CommerceResponse response = event.generateResponse();
            Status status = mTransactionManager.sendEventResponse(response);
            if (status == StatusCode.SUCCESS) {
              // success sending print event response
            } // else handle error ending print event response
        } // else handle failed event status
    } // else handle PrintEvent.RESPONSE_TYPE
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 // Overridden from the CommerceListenerAdapter
override fun handlePrintEvent(event: PrintEvent) {
    if (PrintEvent.REQUEST_TYPE == event.getType()) {
        if (event.getStatus() == StatusCode.SUCCESS) {
            val response = event.generateResponse()
            val status = mTransactionManager.sendEventResponse(response)
            if (status == StatusCode.SUCCESS) {
              // success sending print event response
            } // else handle error sending print event response
        } // else handle failed event status
    } // else handle PrintEvent.RESPONSE_TYPE
}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// Overridden from the VFICommerceListenerAdapter
override func handle(_ event: VFIPrintEvent?) {
    if (VFIPrintEventREQUESTTYPE == event?.getType()) {
        if (VFIStatusCodeSuccess == event?.getStatus()) {
            let response = event?.generateResponse()
            let status = sdk.getTransactionManager()?.sendEventResponse(response)
            if (VFIStatusCodeSuccess == status?.getStatus()) {
                // success sending print event response
            } // else handle error sending print event response
        } // else handle failed event status
    } // else handle VFIPrintEventRESPONSETYPE
}
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> private readonly EventHandler&#x3C;PrintEvent> print_event_handler_;
</strong>
private void HandleEvent(PrintEvent event)
{
    if (event.Type == PrintEvent.REQUEST_TYPE)
    {
        if (event.Status == StatusCode.SUCCESS)
        {
            CommerceResponse response = event.generateResponse();
            response.StatusCode(StatusCode.SUCCESS);
            Status status = payment_sdk_.TransactionManager.SendEventResponse(response);
            if (status == StatusCode.SUCCESS)
            {
              // success sending print event response
            } // else handle error sending print event response
        } // else handle failed event status
    } // else handle PrintEvent.RESPONSE_TYPE
}

// ...
// Link event handler after initialization is complete but before requesting input
print_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};
payment_sdk_.TransactionManager.HandlePrintEvent += Print_event_handler_;
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
class Listener: public verifone_sdk::CommerceListenerAdapter {
 public:
  void handlePrintEvent (
        const std::shared_ptr<verifone_sdk::PrintEvent>& event) override {
    if (event->getType() == verifone_sdk::PrintEvent::REQUEST_TYPE) {
      if (event->getStatus() == StatusCode::SUCCESS) {
        // create print response and send it to terminal
        std::shared_ptr<verifone_sdk::CommerceResponse> print_response =
            event->generateEventResponse();
        response->setStatus(verifone_sdk::StatusCode::SUCCESS);
        auto status = psdk->getTransactionManager()->sendEventResponse(esponse);
        if (status->getStatus() == verifone:sdk::StatusCode::SUCCESS) {
          // success sending print event response
        } // else handle error sending print event response
      } // else handle failed event status
    } // else handle verifone_sdk::PrintEvent.RESPONSE_TYPE
}
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
public void HandlePrintEvent(PrintEvent sdk_event)
{
    if (sdk_event.Type == PrintEvent.REQUEST_TYPE)
    {
        if (sdk_event.Status == 0)
        {
            CommerceResponse response = sdk_event.GenerateEventResponse();
            response.Status = 0;

            Status status;
            mw.Dispatcher.Invoke(() => { status = mw.payment_sdk_.TransactionManager.SendEventResponse(response); });
            if (status == 0)
            {
                // success sending print event response
            } // else handle error sending print event response
        } // else handle failed event status
    } // else handle PrintEvent.RESPONSE_TYPE
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 11: End Session <a href="#end-session" id="end-session"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
private final CommerceListenerAdapter mCommerceListenerAdapter = new CommerceListenerAdapter() {
    @Override
    public void handleTransactionEvent(TransactionEvent event) {
        if (CommerceEvent.SESSION_ENDED.equals(event.getType())) {
          if (event.getStatus() == StatusCode.SUCCESS) {
              // Session Ended.
          } else {
              // Handle failure by examining the status code and message.
          }
        }
    }
}

// ...
// The PaymentSdk must be initialized and should already have a started session

// The listener provided during initialize will receive the event
mPaymentSdk.getTransactionManager().endSession();
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 private val mCommerceListenerAdapter = object : CommerceListenerAdapter() {
    override fun handleTransactionEvent(event: TransactionEvent) {
        if (CommerceEvent.SESSION_ENDED.equals(event.getType())) {
            if (event.getStatus() == StatusCode.SUCCESS) {
                // Session Ended.
            } else {
                // Handle failure by examining the status code and message.
            }
        }
    }
}

suspend fun psdkTransactionManagerLogout()
{
    // The listener provided during initialize will receive the event
    mPaymentSdk.getTransactionManager()!!.endSession()
}

// ...
// The PaymentSdk must be initialized and should already have a started session

// Perform the action using a co-routine.
val job = Job()
val scope = CoroutineScope(Dispatchers.IO + job)
scope.launch {
    psdkTransactionManagerLogout()
}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// Overridden from the VFICommerceListenerAdapter
override func handle(_ event: VFITransactionEvent?) {
    if (VFICommerceEventSESSIONENDED == event?.getType()) {
        if (VFIStatusCodeSuccess == event?.getStatus()) {
            // Session Ended.
        } else {
            // Handle failure by examining the status code and message.
        }
    }
}

let adapter = CommerceListenerAdapter(listener: self)

// ...
// The PaymentSdk must be initialized and should already have a started session

// The listener provided during initialize will receive the event
sdk.getTransactionManager()?.endSession()
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> private void HandleEvent(TransactionEvent event)
</strong>{
    if (event.Type == CommerceEvent.SESSION_ENDED)
    {
        if (event.Status == StatusCode.SUCCESS)
        {
            // Session ended.
        }
        else
        {
            // Handle failure by examining the status code and message.
        }
    }
}

// The listener provided during initialize will receive the event
payment_sdk_.TransactionManager.EndSession();
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
class CommerceAdapter: public verifone_sdk::CommerceListenerAdapter {
 public:
  void handleTransactionEvent(const std::shared_ptr<verifone_sdk::TransactionEvent>& event)
      override {
    if (event->getType() == verifone_sdk::CommerceEvent::SESSION_ENDED) {
      if (event->getStatus() == verifone_sdk::StatusCode::SUCCESS) {
        // Session ended.
      } else {
        // Handle failure by examining the status code and message.
      }
    }
  }
  // ...
}

// ...
// The PaymentSdk must be initialized and should already have a started session

if (auto transaction_manager = psdk->getTransactionManager()) {
  // The listener provided during initialize will receive the event
  transaction_manager->endSession();
}
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
public void HandleTransactionEvent(TransactionEvent sdk_event)
{
    if (sdk_event.Type == CommerceEvent.SESSION_ENDED)
        {
            if (sdk_event.Status == 0)
            {
                // Session ended.
            }
            else
            {
                // Handle failure by examining the status code and message.
            }
        }
}

// The listener provided during initialize will receive the event
payment_sdk_.TransactionManager.EndSession();
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 13: Logout <a href="#logout" id="logout"></a>

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
private final CommerceListenerAdapter mCommerceListenerAdapter = new CommerceListenerAdapter() {
    @Override
    public TransactionEventResponse handleTransactionEvent(TransactionEvent event) {
        if (TransactionEvent.LOGOUT_COMPLETED.equals(event.getType())) {
          if (event.getStatus() == StatusCode.SUCCESS) {
              // Logout is complete.
          } else {
              // Handle failure by examining the status code and message.
          }
        }
    }
}

// ...
// The PaymentSdk must be initialized and should be logged in already

// The listener provided during initialize will receive the event for logout
mPaymentSdk.getTransactionManager().logout();
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 private val mCommerceListenerAdapter = object : CommerceListenerAdapter() {
    override fun handleTransactionEvent(event: TransactionEvent) :
                                        TransactionEventResponse {
        if (TransactionEvent.LOGOUT_COMPLETED.equals(event.getType())) {
            if (event.getStatus() == StatusCode.SUCCESS) {
                // Logout is complete.
            } else {
                // Handle failure by examining the status code and message.
            }
        }
    }
}

suspend fun psdkTransactionManagerLogout()
{
    // The listener provided during initialize will receive the event for logout
    mPaymentSdk.getTransactionManager()!!.logout()
}

// ...
// The PaymentSdk must be initialized and should be logged in already

// Perform the action using a co-routine.
val job = Job()
val scope = CoroutineScope(Dispatchers.IO + job)
scope.launch {
    psdkTransactionManagerLogout()
}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// Overridden from the VFICommerceListenerAdapter
override func handle(_ event: VFITransactionEvent?) {
    if (VFITransactionEventLOGOUTCOMPLETED == event?.getType()) {
        if (VFIStatusCodeSuccess == event?.getStatus()) {
            // Logout is complete.
        } else {
            // Handle failure by examining the status code and message.
        }
    }
}

let adapter = CommerceListenerAdapter(listener: self)

// ...
// The PaymentSdk must be initialized and should be logged in already

// The listener provided during initialize will receive the event for logout
sdk!.getTransactionManager()!.logout()
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> private void HandleEvent(TransactionEvent event)
</strong>{
    if (event.Type == TransactionEvent.LOGOUT_COMPLETED)
    {
        if (event.Status == StatusCode.SUCCESS)
        {
            // Logout is complete.
        }
        else
        {
            // Handle failure by examining the status code and message.
        }
    }
}

// The listener provided during initialize will receive the event for logout
payment_sdk_.TransactionManager.Logout();
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
class CommerceAdapter: public verifone_sdk::CommerceListenerAdapter {
 public:
  void handleTransactionEvent(const std::shared_ptr<verifone_sdk::TransactionEvent>& event) override {
    if (event->getType() == verifone_sdk::TransactionEvent::LOGOUT_COMPLETED) {
      if (event->getStatus() == verifone_sdk::StatusCode::SUCCESS) {
        // Logout is complete.
      } else {
        // Handle failure by examining the status code and message.
      }
    }
  }
  // ...
}

// ...
// The PaymentSdk must be initialized and should be logged in already

if (auto transaction_manager = psdk->getTransactionManager()) {
  // The listener provided during initialize will receive the event for logout
  transaction_manager->logout();
}
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
public void HandleTransactionEvent(TransactionEvent sdk_event)
{
    if (sdk_event.Type == TransactionEvent.LOGOUT_COMPLETED)
    {
        if (sdk_event.Status == 0)
        {
            // Logout is complete.
        }
        else
        {
            // Handle failure by examining the status code and message.
        }
    }
}

// The listener provided during initialize will receive the event for logout
payment_sdk_.TransactionManager.Logout();
```

{% endcode %}
{% endtab %}
{% endtabs %}

***

{% hint style="info" %}
**See also:** For another example in requesting user input, refer to [Inline Tipping with Tip Options.](/psdk-latest/psdk-user-guide-and-training/psdk-user-guide/payment_functions/semi-integrated-payments/advance-flows.md#id6)
{% endhint %}

***

{% columns %}
{% column width="25%" %}

<figure><img src="/files/9ezXRridnCaI1awLr3X9" alt="" width="150"><figcaption></figcaption></figure>
{% endcolumn %}

{% column width="25%" %}

{% endcolumn %}

{% column width="16.66666666666666%" %}
**Version:**\
**Date:**
{% endcolumn %}

{% column width="33.333333333333336%" %} <code class="expression">space.vars.psdk\_version</code>\ <code class="expression">space.vars.psdk\_date</code>
{% endcolumn %}
{% endcolumns %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.verifone.com/psdk-latest/psdk-user-guide-and-training/psdk-user-guide/pay_at_table.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
