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(...)
andTransactionManager.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
orTransaction.REFUND_TYPE
. There can be one or more transactions for an order. There is always one transaction object associated with a Session.
PSDK State Transitions¶
The table below itemizes the available actions and subsequent transition states for each action.
Index |
Actions |
Need Login? |
Need Session? |
TransactionManager Transient State |
TransactionManager Final State (Success/Failure) |
---|---|---|---|---|---|
1 |
Initialize |
No |
No |
NA |
NOT_LOGGED_IN/UNKNOWN |
2 |
Login |
No |
No |
LOGGING_IN |
LOGGED_IN/NOT_LOGGED_IN |
3 |
StartSession |
Yes |
No |
SESSION_OPENING |
SESSION_OPEN/LOGGED_IN |
4 |
HandleLineItem |
Yes |
Yes |
AWAITING_TERMINAL |
No state change |
5 |
FinalizeBasket |
Yes |
Yes |
AWAITING_TERMINAL |
No state change |
6 |
PresentReceiptOptions |
Yes |
Yes |
AWAITING_TERMINAL |
No state change |
7 |
RequestCardData |
Yes |
Yes |
AWAITING_TERMINAL |
No state change |
8 |
PerformStoredValueAction |
Yes |
Yes |
AWAITING_TERMINAL |
No state change |
9 |
PerformPayment |
Yes |
Yes |
PAYMENT_PROCESSING |
No state change |
10 |
HandleResponse |
Yes |
Yes |
PAYMENT_PROCESSING |
No state change |
11 |
EndSession |
Yes |
Yes |
NA |
LOGGED_IN |
12 |
Reconcile |
Yes |
No |
AWAITING_TERMINAL |
No state change |
13 |
QueryTransactions |
Yes |
No |
AWAITING_TERMINAL |
No state change |
14 |
ReprintReceipt |
Yes |
No |
NA |
No state change |
15 |
Logout |
Yes |
No |
NA |
NOT_LOGGED_IN |
16 |
PresentContent |
No |
No |
NA |
No state change |
17 |
RequestInput |
No |
No |
AWAITING_TERMINAL |
No state change |
18 |
DeviceManagementCommand |
No |
No |
AWAITING_TERMINAL |
No state change |
19 |
GetState |
No |
No |
NA |
synchronous, no state change |
20 |
QueryCapability |
No |
No |
NA |
No state change |
21 |
Abort |
No |
No |
NA |
No state change |
22 |
No |
No |
NA |
No state change |
|
23 |
Encryption |
No |
No |
AWAITING_TERMINAL |
No state change |
24 |
DeviceVitals |
No |
No |
NA |
No state change |
25 |
Pin |
No |
No |
NA |
No state change |
26 |
Teardown |
No |
No |
NA |
UNKNOWN |
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.
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. Logically, it would seem that if this immediate result returns an error status, the listener would not receive any event for the call. In practice, however, PSDK does send an asynchronous event to the listener in these situations. This can cause confusion for the user, and will be addressed in future PSDK releases.
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 PSDK State Transitions).
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.
See also
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
The Payment SDK does not keep the listeners from being destroyed. It is the responsibility of the POS to maintain a valid reference to the listeners while they need to be active.
CommerceListener
andPsdkStatusListener
are being deprecated. Please see Migration from CommerceListener and PsdkStatusListener to CommerceListenerAdapter.
See also
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(); |
See also
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 } |
Verifone Confidential
This documentation is protected by law from any form of duplication unless prior permission is obtained from the officers of Verifone.
Verifone Payment SDK v3.55.5