POS Integration Guide


Concepts

The SDK has a few core concepts before we get started.

Definitions

  • POS - The Android application using the SDK. This may or may not be an actual Point-of-Sale application. This application is generally used by a cashier or employee of the merchant.

  • POI - The point of interaction for the end customer, this is the device that collects card information and other similar input.

  • Payment Service - A background service running on the Android system that receives the calls from the SDK and either handles it directly or adapts it to the protocol used by the POI.

  • Payment App - The application running on the POI that handles the card information and other payment / transaction details, communicating this to the host to authorize the payment, or storing the data for later and issuing a temporary approval if offline authorization is enabled.

  • Host / Payment Host - Receives the card data and other information from the Payment App, and actually enables the funds to be transferred. This can be a payment gateway, processor, etc.

  • Session - The period between TransactionManager.startSession(...) and TransactionManager.endSession() where the POI is reserved for the POS, blocking anything else from performing operations with the POI, and keeping the screen in a ready state to display information from the POS.

  • Order - A collection of basket items and payments that are related by the same Invoice, linking the original basket items, refunded/replaced items, and all of the associated payments such as sales, pre-auths, pre-auth completions, voids, refunds, etc. There is no explicit object in the SDK for an order, it is an abstract concept represented by a single Invoice ID.

  • Transaction - A collection of basket items and payments that are related by the same Invoice for a specific purpose. Similar to an Order, except that it has a type which defines its purpose, such as Transaction.PAYMENT_TYPE or Transaction.REFUND_TYPE. There can be one or more transactions for an order. There is always one transaction object associated with a Session.

State Matters

There are 3 states in particular, TransactionManager.STATE_LOGGED_IN, TransactionManager.STATE_SESSION_OPEN, and TransactionManager.STATE_PAYMENT_PROCESSING. Some commands will only work in a specific state, though commands that work in an earlier state will also work in a later state (except for TransactionManager.STATE_PAYMENT_PROCESSING). For example, ReportManager.queryTransactions(query) will work once logged in, as well as during a session and the transitions between, but will not work while a payment is in progress, because the POI is completely dedicated to handling the payment during that state. The current state can be synchronously retrieved using TransactionManager.getState().

Logging in (TransactionManager.login(...)) informs the POI that a cashier is present, and enables the POI to download/configure itself based on the cashier ID.

Starting a session (TransactionManager.startSession(...)) reserves the POI for use by the POS, enabling an order to be built and payments to be processed. There should only be one “order” per session, where an order is an optional collection of basket items and a set of payments/refunds/voids, all associated with a single Invoice ID. It is acceptable to manage a single order across multiple sessions, but it’s not recommended to handle multiple orders within a single session.

Starting a payment or performing some other payment-related action will move it to the payment processing state.

@startuml
!include uml_styles.iuml
hide footbox

participant POS order 10
participant PSDK order 20
|||
POS -> PSDK: PaymentSdk.getTransactionManager()
POS ->> PSDK: transactionManager.login()
POS <<- PSDK: TransactionEvent.LOGIN_COMPLETED
group STATE_LOGGED_IN
  POS ->> PSDK: transactionManager.startSession()
  group STATE_SESSION_OPEN
    POS <<- PSDK: CommerceEvent.SESSION_STARTED
    POS <<->> PSDK: update POI display with basket items
    POS ->> PSDK: transactionManager.startPayment()
    group STATE_PAYMENT_PROCESSING
      POS <<- PSDK: TransactionEvent.TRANSACTION_PAYMENT_STARTED
      ...notifications/other messages...
      POS <<- PSDK: TransactionEvent.TRANSACTION_PAYMENT_COMPLETED
    end
    == Repeat payments until full payment is collected ==
    POS ->> PSDK: transactionManager.endSession()
    POS <<- PSDK: CommerceEvent.SESSION_ENDED
  end
  == Repeat sessions until cashier logs out ==
  ...
  POS ->> PSDK: transactionManager.logout()
  POS <<- PSDK: TransactionEvent.LOGOUT_COMPLETED
end
|||

@enduml

Note

There are some actions that can be performed without a session active but after login, primarily actions on the ReportManager. Other actions, related to setting parameters such as TransactionManager.setDeviceParams(Map) or TransactionManager.getDeviceInformation() can be performed even before login.

All calls are asynchronous (except a few)

Nearly all of the calls are asynchronous, returning an immediate value to indicate if the call could be successfully transmitted, and later returning the actual result to the listener. The immediate value returned only indicates if it was possible to send the call across the bound interface and that the bound interface is in a state to accept the call and queue it to be sent to the POI. If this immediate result returns an error status, the listener will not receive any event for the call.

The asynchronous calls are placed into a queue, so if one were to call login(), startSession(), startPayment(), the payment would be properly handled if the preceding calls succeeded without error, otherwise they are going to fail due to a state issue (see state-matters).

The exceptions to this rule do not require communication with the POI, allowing the result to be returned immediately. These are listed below.

Separate Processes means Separate Objects

The Services are separate processes, which means that the memory is separate. Each API call to a processes marshalls and unmarshalls the objects across the process boundary, meaning that each application has a copy of the objects being used. This can be confusing and lead to mistakes while programming, such as setting a field on an object within the POS and expecting it to be set within the Payment Service, or modifying an object locally without using the latest version of that object from the service, and causing a merge issue. The services can perform most of the basic merges necessary to run easily, but it’s important to remember that if an object is changed locally and the update needs to be reflected in the service, this object must be sent to the service using one of the API calls defined. It is also important to keep local copies updated with or replaced by the latest objects received by the listener.



Best Practices

User Inactivity

It is important that a session not be kept open without any interaction, as it blocks the POI from performing important internal updates and prevents any other application from being able to use the device. We recommend ending the session if the cashier is inactive somewhere between 10 and 30 seconds. It can be good to immediately start a session once a previous session is ended, this can help a cashier dealing with a long line and needing to key in orders rapidly, but if the cashier is not doing anything, please end the session.

Threads of Execution

It is generally best to interact with the PSDK from some context which is different than the UI. While most calls in to the PSDK will not block for long, there are a couple that might delay UI execution, such as initialization.

It is also important that when events are received, the actual processing of the event happen in a separate context from the one which received the event. We only send events from one thread, so any long processing of one event will delay subsequent events from being received. This is generally not desirable behavior.

Finally, when running on Android or Java, it is best for all calls into the PSDK be performed from a single thread/context. On these platforms, calls into the PSDK attach to the JVM, which can be an expensive operation, but contexts which have already attached do not need to perform that operation on subsequent calls.



Getting Started


Initialize Payment SDK and Get Transaction Manager

The first step is to create and initialize the Payment SDK, after which an instance of the TransactionManager can be acquired. The Payment SDK may be initialized in server mode, in which it listens for a connection from the payment device, or client mode, in which it connects to a specified payment device. In client client/server description, no context passed to getDeviceInformation() mode, the Payment SDK may be connecting to a payment device under three scenarios: the first connection, in which the address information of the target device must be specified, a subsequent connection, in which the previous connection information is persisted, or a changed target address, in which the persisted connection information must be wiped out, and replaced with the new connection information. Each of these scenarios is depicted below in the code samples. These code samples are organized to easily perform the initialization from the background, but this can be done in a variety of ways, and should be consistent with the existing design instead of doing this exact code.

Client Mode Initialization

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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<>();

            // Specify the connection type and address
            paramMap.put(PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY, "tcpip");
            paramMap.put(PsdkDeviceInformation.DEVICE_ADDRESS_KEY, "192.168.1.10");
            mPaymentSdk.initializeFromValues(mCommerceListenerAdapter, paramMap);
        }
    }.execute(someContext);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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)

    // Specify the connection type and address
    val paramMap: HashMap<String, String> = hashMapOf(
        PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY to "tcpip",
        PsdkDeviceInformation.DEVICE_ADDRESS_KEY to "192.168.1.10"
    )
    mPaymentSdk.initializeFromValues(mCommerceListenerAdapter, paramMap)
}

private fun getStarted() {
    val job = Job()
    val scope = CoroutineScope(Dispatchers.IO + job)
    scope.launch {
        // first connection
        psdkInit(false, false, context)
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 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)

    // Specify the connection type and address
    let connectConfig = [
        // Specify the connection type and address
        VFIPsdkDeviceInformationDEVICECONNECTIONTYPEKEY: "tcpip",
        VFIPsdkDeviceInformationDEVICEADDRESSKEY: "192.168.1.10"]
    sdk.initialize(fromValues: adapter, config: connectConfig)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using PaymentSDK;
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();

    // Specify the connection type and address
    var param_map = new Windows.Foundation.Collections.StringMap
    {
        {PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY, "tcpip"},
        {PsdkDeviceInformation.DEVICE_ADDRESS_KEY, "192.168.1.10"}
    };
    payment_sdk_.InitializeFromValues(param_map);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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() {
  // 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::PsdkDeviceInformation::DEVICE_ADDRESS_KEY, "192.168.1.10"},
      {verifone_sdk::PsdkDeviceInformation::DEVICE_CONNECTION_TYPE_KEY, "tcpip"}};

  payment_sdk_->initializeFromValues(adapter_, param_map);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using VerifoneSdk;

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();

    // Specify the connection type and address
    var param_map = new Dictionary<string, string>
    {
        { "DEVICE_ADDRESS_KEY", "192.168.0.10" },
        { "DEVICE_CONNECTION_TYPE_KEY", "tcpip" }
    };
    payment_sdk_.InitializeFromValues(param_map);
}

Server Mode Initialization

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 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)
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 using PaymentSDK;
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);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 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);
}

Device setup via Bluetooth

To connect via Bluetooth or Bluetooth PAN using tethering, the Bluetooth Device Setup functionality will allow pairing with a new device and will prompt the user with messages if necessary bluetooth settings are not enabled.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func psdkLaunchBluetoothDeviceSetup() {
    // Create PaymentSdk
    let sdk = VFIPaymentSdk.createPaymentSdk()

    // Launch the Bluetooth device setup flow.
    // Note: If callback received a successful status, the bluetooth device was paired
    // and saved successfully. Calling initializeFromValues() will
    // initialize PaymentSdk with the new device.
    // btpan: Using Bluetooth PAN?
    // sdi: Connecting to a SDI terminal?
    // caller: Calling view ViewController
    // listener: Handler that implements the callback
    sdk?.setupBluetoothDevice(btpan: true, sdi: true, caller: self, listener: self)
}

// Callback for handling Bluetooth device setup
extension ViewController: VFIBluetoothDeviceSetupListener {
    func foundBluetoothDevice(status: VFIBluetoothSetupStatus, device: VFIPsdkDeviceInformation?) {
        // handle different return status codes
    }
}

Connecting to a New Device

In the situation in which a previously connected device is being replaced, if the logical ID of the new device as assigned by VHQ is different than the original logical ID, or if the original device did not have a logical ID, then the old device information must be wiped out of persistent storage and initialized with a configuration which contains the new information. The code sample below assumes a client mode initialization.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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 psdkConnectToNewDevice() {
    new AsyncTask<Context, Void, Void>(){
        @Override
        protected Void doInBackground(Context... contexts) {
            // Create PaymentSdk
            mPaymentSdk = PaymentSdk.create(contexts[0]);
            PsdkDeviceInformation current = mPaymentSdk.getDeviceInformation();
            if (!current) {
                // there is no known last device
                return;
            }
            // Forget current device
            mPaymentSdk.UseDevice(current, false);
            HashMap<String, String> paramMap = new HashMap<>();
            // Specify the connection type and address
            paramMap.put(PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY, "tcpip");
            paramMap.put(PsdkDeviceInformation.DEVICE_ADDRESS_KEY, "192.168.1.10");
            mPaymentSdk.initializeFromValues(mCommerceListenerAdapter, paramMap);
        }
    }.execute(someContext);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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 psdkConnectToNewDevice(context: Context) {
    // Create PaymentSdk
    mPaymentSdk = PaymentSdk.create(context)
    val current = mPaymentSdk.getDeviceInformation()
    if (!current) {
        // there is no known last device
        return
    }
    // Forget current device
    mPaymentSdk.UseDevice(current, false)
    // Specify the connection type and address
    val paramMap: HashMap<String, String> = hashMapOf(
        PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY to "tcpip",
        PsdkDeviceInformation.DEVICE_ADDRESS_KEY to "192.168.1.10"
    )
    mPaymentSdk.initializeFromValues(mCommerceListenerAdapter, paramMap)
}

private fun getStarted() {
    val job = Job()
    val scope = CoroutineScope(Dispatchers.IO + job)
    scope.launch {
        // first connection
        psdkInit(false, false, context)
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 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 psdkConnectToNewDevice() {
    // Create PaymentSdk
    let sdk = VFIPaymentSdk.createPaymentSdk()
    let adapter = CommerceListenerAdapter(listener: self)

    if let current = sdk.getDeviceInformation() {
        // Forget current device
        sdk.useDevice(current, saveDevice: false)
    } else {
        // there is no known last device
        return
    }
    let connectConfig = [
        // Specify the connection type and address
        VFIPsdkDeviceInformationDEVICECONNECTIONTYPEKEY: "tcpip",
        VFIPsdkDeviceInformationDEVICEADDRESSKEY: "192.168.1.10"]
    sdk.initialize(fromValues: adapter, config: connectConfig)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using PaymentSDK;
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 PsdkConnectToNewDevice()
{
    // Create PaymentSdk
    payment_sdk_ = new PaymentSdk();

    var current = payment_sdk_.DeviceInformation;
    if (current == null)
    {
        // There is no known last device.
        return;
    }
    // Forget current device
    payment_sdk_.UseDevice(current, false);
    // Specify the connection type and address
    var param_map = new Windows.Foundation.Collections.StringMap
    {
        {PsdkDeviceInformation.DEVICE_CONNECTION_TYPE_KEY, "tcpip"},
        {PsdkDeviceInformation.DEVICE_ADDRESS_KEY, "192.168.1.10"}
    };
    payment_sdk_.InitializeFromValues(param_map);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 psdkConnectToNewDevice() {
  // Create PaymentSdk
  payment_sdk_ = verifone_sdk::PaymentSdkInterface::create(
      verifone_sdk::CreatePlatformContextLinux(std::nullopt));
  auto adapter_ = std::make_shared<CommerceAdapter>();

  auto current = payment_sdk_->getDeviceInformation();
  if (!current) {
    // There is no known last device.
    return;
  }
  // Forget current device
  payment_sdk_->UseDevice(*current, false);

  // Specify the connection type and address
  std::unordered_map<std::string, std::string> param_map{
      {verifone_sdk::PsdkDeviceInformation::DEVICE_ADDRESS_KEY, "192.168.1.10"},
      {verifone_sdk::PsdkDeviceInformation::DEVICE_CONNECTION_TYPE_KEY, "tcpip"}};

  payment_sdk_->initializeFromValues(adapter_, param_map);
}
1
// To be defined

Note

TransactionManager.getTransactionManager() is no longer available. Please see Migration from PSDK 2.x to 3.x.

Create a Commerce Listener

A listener must be created so that the Paymentsdk Initialize and Teardown status are available for the POS. It also processes various events derived from CommerceEvent. There must be at least one valid listener while a session is open, the last listener cannot be removed during this state. The listener must be passed to PaymentSdk.initialize(...), PaymentSdk.initializeFromValues(...) and PaymentSdk.initializeFromFile(...)

Create the CommerceListenerAdapter. The POS can override handle methods that it is interested in. The event type can be determined by calling the CommerceEvent.getType() method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
private final CommerceListenerAdapter mCommerceListenerAdapter = new CommerceListenerAdapter() {
    // Override only the methods that the POS is interested in.
    @Override
    public void handleStatus(Status status) {

    }

    @Override
    public void handleCommerceEvent(CommerceEvent event) {

    }

    @Override
    public void handleTransactionEvent(TransactionEvent event) {

    }

    ...

};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
private val mCommerceListenerAdapter = object : CommerceListenerAdapter() {
    // Override only the methods that the POS is interested in.
    override fun handleStatus(status: Status) {

    }

    override fun handleCommerceEvent(event: CommerceEvent) {

    }

    override fun handleTransactionEvent(event: TransactionEvent) {

    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class PaymentSdkListener: VFICommerceListenerAdapter {
    // Override only the methods that the POS is interested in from the VFICommerceListenerAdapter.
    override func handle(_ status: VFIStatus?) {

    }

    override func handle(_ event: VFICommerceEvent?) {

    }

    override func handle(_ event: VFITransactionEvent?) {

    }

    ...
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
private readonly EventHandler<Status> sdk_payment_event_handler_;
private readonly EventHandler<BasketEvent> basket_event_handler_;
private readonly EventHandler<CommerceEvent> commerce_event_handler_;
private readonly EventHandler<ReconciliationEvent> reconcilliation_event_handler_;
private readonly EventHandler<TransactionEvent> transaction_event_handler_;
// Declare the remaining event handlers

sdk_payment_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};

basket_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};

commerce_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};

transaction_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};

reconciliation_event_handler_ = async (sender, args) =>
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => HandleEvent(args));
};

// Continue creating the remaining event handlers

// Construct event handler for initialization
sdk_payment_event_handler_ = async (sender, args) =>
{
    if (args.Status == StatusCode.SUCCESS) {
        // Initialization succeeded, attach other event handlers.
        payment_sdk_.HandlePaymentSdkEvent += sdk_payment_event_handler_;
        payment_sdk_.HandleBasketEvent += basket_event_handler_;
        payment_sdk_.HandleCommerceEvent += commerce_event_handler_;
        payment_sdk_.HandleTransactionEvent += transaction_event_handler_;
        payment_sdk_.HandleReconciliationEvent += reconcilliation_event_handler_;
        // Attach the remaining event handlers.
    } // Else initialization failed.
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class CommerceAdapter : public verifone_sdk::CommerceListenerAdapter {
// Override only the methods that the POS is interested in.
 public:
  void handleStatus(const std::shared_ptr<verifone_sdk::Status> & status) override {
    // Process status
  }

  void handleCommerceEvent(const std::shared_ptr<verifone_sdk::CommerceEvent>& event) override {
    // Process event
  }

  void handleTransactionEvent(const std::shared_ptr<verifone_sdk::TransactionEvent>& event) override {
    // Process event
  }

    ...

}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
//Inherit and implement the methods in CommerceListener2
public class Listener : CommerceListener2 {

    public void HandleStatus(Status status) {
        // Process status
    }

    public void HandleCommerceEvent(CommerceEvent sdk_event) {
        // Process event
    }

    public void HandleDeviceManagementEvent(DeviceManagementEvent sdk_event) {
        // Process event
    }

      ...
}

Note

Login / Logout

After initialization is complete, the transaction manager can be retrieved. Once the transaction manager is obtained and bound, it’s time to login. The login and logout calls should match the presence of the cashier at the station, when the cashier logs in to the device, call TransactionManager.loginWithCredentials(), if the cashier logs out or is logged out automatically, call TransactionManager.logout(). If there is no authentication mechanism for the cashier, then login should be called when the device wakes, and logout when the device sleeps.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
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);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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()
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private readonly EventHandler<TransactionEvent> transaction_event_handler_;

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 = new OptionalString("username");
var result = payment_sdk_.TransactionManager.LoginWithCredentials(credentials);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
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();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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()
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 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()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
private void HandleEvent(TransactionEvent event)
{
    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();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
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();
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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();

Start a Session

After login, it is necessary to start a session for the transaction. An instance of the CommerceListenerAdapter which was passed in the PaymentSdk.initialize() method acts as the listener for events passed back from TransactionManager. Building on the example above, after login is completed we can start the session. Once we have a session open, items can be added to the POI display and payments can be processed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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()
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 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
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private readonly EventHandler<TransactionEvent> transaction_event_handler_;

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
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
}