Guides
Log In
Guides

How to Integrate

Overview

This scenario walks you through how to integrate Moneris Go devices with your Restaurant Management System (RMS) to support Pay-at-Table. The goal is to allow servers to retrieve a list of their open tables, view table details, accept card payments (including tips) at the table and automatically update the RMS. This improves efficiency, eliminates manual errors, and enhances the guest checkout experience.

By the end, your RMS will be able to communicate with Moneris’ RMS API and Moneris Go terminals to complete an in-person payment flow.


Device Compatibility

Go Pay-at-Table is available on the following Moneris Go terminals:


📘

Note

If you do not have access to any of the above test terminals, click below to order a Moneris Go test terminal and test cards.

Order a Device


Use Case Overview

In many restaurants, servers need to accept payments directly at a guest’s table. This scenario uses Moneris Go Android devices running the Go Pay-at-Table application to make that possible.

The Moneris Go terminal acts as a bridge between the merchant’s RMS and Moneris’ payment infrastructure:

  • The RMS connects to Moneris’ RMS cloud API to send and receive table/payment data.
  • The Moneris Go Pay at Table runs on the Android terminal and allows customers to complete card transactions at the table.

📘

Note

Every message received or sent from RMS has two-byte header in front of JSON payload, network byte order (big-endian), containing the message length.

See twoBytesHeaderAppender and twoBytesHeaderTrimmer in the full code example section.


The key tasks your integration needs to support:

  1. Connecting the RMS to Moneris (authenticate)
  2. Maintain the connection using (echo)
  3. Retrieving the server’s tables (getTables)
  4. Getting check info for a selected table (getTable)
  5. Applying the payment and updating the RMS (applyPayment)

Prerequisites

  • A Moneris Go terminal with Pay-at-Table installed
  • Your assigned merchantId and apiToken from Moneris
  • Terminal ID (terminalId) configured for your device
  • RMS server that implements the RMS message structure
  • A list of open tables available in your RMS that can be queried by serverId

📘

App Setup

To download and set up the Pay-at-Table app, click here to view the Help Centre article.

Help Centre Article


1: Authenticate the RMS with Moneris

Purpose:

Before any table or payment data can be exchanged, your RMS must authenticate with Moneris. This happens when a persistent TLS socket connection is opened between your RMS implementation and Moneris’ cloud server. The authenticate request registers your merchant credentials and establishes a secure session. A single connection per MerchantId (MID) is allowed. All subsequent connection attempts will be rejected if there is an active session with the same MID.


Required Inputs:

  • merchantId (V13): Your unique 13-digit Moneris merchant number, starts with 0030
  • apiToken (V50): Secure credential provided by Moneris
  • cloudApiVersion (V20): Typically "1.0"
  • requestId (V50): A unique identifier combining terminal ID, timestamp, and sequence number
  • requestTimestamp (F19): ISO timestamp of the request (UTC)

Request Example:


{
  "action": "authenticate",
  "apiToken": "P14i5WS4P0uhgbrnN7BZ",
  "cloudApiVersion": "1.0",
  "merchantId": "1234567890",
  "requestId": "I9000001-20250707-001",
  "requestTimestamp": "2025-07-07 10:00:00"
}

Expected Output:

A successful response returns a status of "200" with your merchantId, verifying you are authenticated.


{
  "status": "200",
  "statusDesc": "OK"
}

📘

authenticate Command

View the full API Specifications for this command

View the Specifications


2: Maintain the Connection Using Echo

Purpose:

Once authenticated, your RMS must keep the session alive by sending an echo message every 30 seconds. If no echo is received, Moneris will drop the connection.


Required Inputs:

Use the same authentication headers as in step 1:

  • merchantId
  • apiToken
  • cloudApiVersion
  • requestId and requestTimestamp

Request Example:


{
  "action": "echo",
  "apiToken": "P14i5WS4P0uhgbrnN7BZ",
  "cloudApiVersion": "1.0",
  "merchantId": "1234567890",
  "requestId": "I9000001-20250707-002",
  "requestTimestamp": "2025-07-07 10:00:30"
}

Expected Output:

Same structure as the authenticate response—confirming the session is active.


📘

echo Command

View the full API Specifications for this command

View the Specifications


3: Retrieve a List of Open Tables

Purpose:

After the server logs into the terminal (via ID entry or card swipe), the Go Pay at Table app sends a getTables request to the RMS to fetch that server’s open tables. These are the tables they’re responsible for, and each table includes the current total and remaining balance.

This API call is used immediately after login or at any point where a server wants to view active tables under their profile. It’s typically triggered when loading the main screen of the Go Pay-at-table interface.


Required Inputs:

  • terminalId (V8): Unique ID assigned to the terminal
  • merchantId (V13)
  • apiVersion (V20): e.g., "1.0"
  • requestId, requestTimestamp
  • serverId (V50): The ID entered or swiped on the terminal

Request Example:


{
  "terminalId": "I9000001",
  "merchantId": "1234567890",
  "apiVersion": "1.0",
  "requestId": "I9000001-20250707-003",
  "requestTimestamp": "2025-07-07 10:01:00",
  "action": "getTables",
  "data": {
    "server": {
      "serverId": "1234"
    }
  }
}

Expected Output:

An array of table objects, each with:

  • tableId – used for lookup
  • tableName – what’s displayed on the terminal (e.g., “Patio-4”, “Main Hall-7”)
  • tableTotalAmount – full balance in cents
  • tableRemainingAmount – amount left to pay in cents


{
  "status": "200",
  "data": {
    "tables": [
      {
        "tableId": "T123",
        "tableName": "Patio-4",
        "tableTotalAmount": 6400,
        "tableRemainingAmount": 6400
      },
      {
        "tableId": "T124",
        "tableName": "Main Hall-7",
        "tableTotalAmount": 8200,
        "tableRemainingAmount": 3200
      }
    ]
  }
}

📘

getTables Command

View the full API Specifications for this command

View the Specifications


4: Retrieve Check Details for a Table

Purpose:

Once a table is selected, the Go Pay at Table sends a getTable request to the RMS to fetch all payment details for that table.


Required Inputs:

  • tableId from the previous step
  • serverId (optional if swiped)
  • terminalId, merchantId, apiVersion, etc.

NOTE: Split by amount and split by check/seat methods will only be supported if enabled through the Go Pay at Table application’s Settings menu.


Request Example:


{
  "terminalId": "I9000001",
  "merchantId": "1234567890",
  "apiVersion": "1.0",
  "requestId": "I9000001-20250707-004",
  "requestTimestamp": "2025-07-07 10:01:10",
  "action": "getTable",
  "data": {
    "server": {
      "serverId": "1234"
    },
    "tableId": "T123"
  }
}

Expected Output:

Includes:

  • splitMethod: 1 = full check, 2 = split by amount, 3 = split by check/seat
  • masterCheck: Total balance
  • Optional checks[]: If the RMS has already split the check by guest


{
  "status": "200",
  "data": {
    "table": {
      "tableName": "Patio-4",
      "tableTotalAmount": 6400,
      "splitMethod": 1,
      "masterCheck": {
        "checkId": "1",
        "checkName": "Full Table",
        "totalAmount": 6400,
        "remainingAmount": 6400
      }
    }
  }
}

📘

getTable Command

View the full API Specifications for this command

View the Specifications


Handling Split Payments

The Pay-at-Table flow supports three payment modes, determined by the splitMethod field returned in the getTable response:

If your RMS supports split payments, follow the instructions below for splitMethod 2 and 3.


splitMethodDescription
1Full check (default)
2Split by amount
3Split by check/seat (per guest)

Split-by-Amount (splitMethod = 2)

Split-by-Check/Seat (splitMethod = 3)

This mode allows multiple guests to pay custom amounts toward a shared check. Go Pay at Table presents a screen for servers or guests to enter the partial payment amount.

Steps:

  1. Receive splitMethod = 2 in the getTable response.
  2. Prompt the user to enter a partial payment amount.
  3. For each payment:
    • Set checkId to the master check (e.g., "1")
    • Use paidAmount to indicate the portion being paid
    • Send an applyPayment request as normal
  4. Repeat until the remainingAmount and tableRemainingAmount both reach 0.

This mode is used when the table is split into separate checks for each guest/seat (e.g., “Check 1 – John”, “Check 2 – Mary”).

Steps:

  1. Receive splitMethod = 3 and a checks[] array in the getTable response.
  2. Display the list of checks to the server or guest.
  3. For each check:
    • Use the appropriate checkId
    • Apply a payment using applyPayment for that check only
  4. Repeat the process for each unpaid check.

Important:

A check/seat is considered closed when its remainingAmount is 0. The full table closes when all checks/seats are paid.

This additional handling ensures your RMS system supports a full range of real-world dining scenarios—from group bills to separate tabs—while maintaining a consistent integration with the Moneris Go platform


Request Example:


{
  "terminalId": "I9000001",
  "merchantId": "1234567890",
  "apiVersion": "1.0",
  "requestId": "I9000001-20250707-004",
  "requestTimestamp": "2025-07-07 10:01:10",
  "action": "getTable",
  "data": {
    "server": {
      "serverId": "1234"
    },
    "tableId": "T123"
  }
}

Expected Output


{
  "terminalId": "I4123456",
  "merchantId": "00312312312312",
  "configCode": "C12345678SI",
  "requestId": "I4123456-2025-08-18-002",
  "responseTimestamp": "2025-08-18 10:01:00",
  "status": "200",
  "statusDesc": "OK",
  "data": {
    "table": {
      "tableId": "01",
      "tableName": "Table 1",
      "tableTotalAmount": 4200,
      "tableRemainingAmount": 4200,
      "splitMethod": 3,
      "masterCheck": {
        "checkId": "1",
        "checkName": "Full Table",
        "totalAmount": 4200,
        "preTaxAmount": 0,
        "remainingAmount": 4200,
        "receipt": {
          "taxes": [],
          "discounts": [],
          "lineItems": []
        }
      },
      "checks": [
        {
          "checkId": "1",
          "checkName": "Check 1",
          "totalAmount": 2000,
          "preTaxAmount": 0,
          "gratuity": 0,
          "remainingAmount": 2000,
          "receipt": {
            "taxes": [],
            "discounts": [],
            "lineItems": []
          }
        },
        {
          "checkId": "2",
          "checkName": "Check 2",
          "totalAmount": 2200,
          "preTaxAmount": 0,
          "remainingAmount": 2200,
          "receipt": {
            "taxes": [],
            "discounts": [],
            "lineItems": []
          }
        }
      ]
    }
  }
}

5: Apply a Payment to the POS

Purpose:

After the customer completes a card payment (tip included) using the Moneris Go terminal, the Go Pay-at-Table sends an applyPayment message to finalize the transaction and update the check total.


Required Inputs:

  • tableId, checkId: From step 4
  • tenderType: "CARD" or "CASH"
  • If CARD, you must include:
    • cardType (VISA, MC, AMEX, etc.)
    • authNumber: Approval code
    • referenceNumber: Transaction ID
    • lastDigits: Last 4 of the PAN
  • paidAmount: Approved amount in cents
  • tipAmount: Optional tip in cents

Request Example:

NOTE: paidAmount is inclusive of tipAmount


{
  "terminalId": "I9000001",
  "merchantId": "1234567890",
  "apiVersion": "1.0",
  "requestId": "I9000001-20250707-005",
  "idempotencyKey": "74ae1696-b1e3-4328-af6d-f1e04d947a13",
  "requestTimestamp": "2025-07-07 10:02:00",
  "action": "applyPayment",
  "data": {
    "server": {
      "serverId": "1234"
    },
    "check": {
      "tableId": "T123",
      "checkId": "1"
    },
    "payment": {
      "tenderType": "CARD",
      "card": {
        "cardType": "VISA",
        "authNumber": "183235",
        "referenceNumber": "1020293",
        "lastDigits": "1234"
      },
      "paidAmount": 5400,
      "tipAmount": 1000
    }
  }
}

Expected Output:

The remainingAmount and tableRemainingAmount should decrease accordingly. When both reach 0, the table is considered closed.


{
  "status": "200",
  "data": {
    "table": {
      "tableId": "T123",
      "tableRemainingAmount": 0
    },
    "check": {
      "checkId": "1",
      "remainingAmount": 0
    }
  }
}

📘

applyPayment Command

View the full API Specifications for this command

View the Specifications


Additional Notes:

  • All monetary fields (paidAmount, tipAmount, totalAmount) are in cents.
  • If tableRemainingAmount > 0 after payment, the same flow can repeat until fully paid.
  • Errors (e.g., invalid table ID or missing field) are returned with a status and statusDesc.

6. Full code example

Below is the full code example in JavaScript


import tls from 'tls';

let displayecho = true;

let intervalConnect = null;
let cloud_sock = null;
const ActionType = {
    echo: 'echo',
    authenticate: 'authenticate',
    getTables: 'getTables',
    getTable: 'getTable',
    applyPayment: 'applyPayment',
};

const errCodesMsgsMap = {
    '218': 'Unsupported action	Action not supported.',
    '600': 'Internal Error',         // 600
    '601': 'Incorrect Msg Length',   // 601
    '602': 'JSON Parse Error',       // 602
    '603': 'Missing Server ID',      // 603
    '604': 'Invalid Server ID',      // 604
    '605': 'Invalid Server Tracks',  // 605
    '606': 'Missing Table ID',       // 606
    '607': 'Invalid Table ID',       // 607
    '608': 'Missing Check ID',       // 608
    '609': 'Invalid Check ID',       // 609
    '610': 'Missing Payment Obj',    // 610
    '611': 'Invalid Payment Obj',    // 611
    '612': 'Missing IdempotencyKey', // 612
    '613': 'Invalid split method',   // 613
    '614': 'Server Not Found',       // 614
    '615': 'No Table Found',         // 615
    '616': 'No Check Found'          // 616
};
const options = {
    autoconnect: true,
    reconnection: true,
    reconnectionDelay: 1000,
    reconnectionDelayMax: 2000,
    reconnectionAttempts: Infinity
};
const cloudSever = {
    host: 'patposct.moneris.com',
    port: 443
}


const getMID = function () {
    return '0030128923365';  //your MID
};

const getCfgCode = function () {
    return "C000497ECP";
};

const getApiToken = function () {
    return 'C7jZF1ad7IIGCoEIMGoD';
}
let getRequestId = function () {
    let now = new Date();
    return getMID() + '-' + now.toISOString();
};
let getDateTime = function () {
    const now = new Date();
    return now.toISOString().replace('T', '-').substring(0, 19);
};
//handle "echo" every 30 seconds 
function startEchoInterval(cloud_sock) {
   
    // Make sure we don't start multiple intervals
    if (cloud_sock.echoInterval) {
        clearInterval(cloud_sock.echoInterval);
    }

    cloud_sock.echoInterval = setInterval(() => {
        if (cloud_sock.gotEchoNoResponse === 0) {
            if (!cloud_sock.echoTimeout) {
                // set 10 sec for timeout to recevice echo response
                cloud_sock.echoTimeout = setTimeout(() => {
                    console.info('Timeout, closing connection....');
                    clearInterval(cloud_sock.echoInterval);
                    clearTimeout(cloud_sock.echoTimeout);
                    cloud_sock.echoTimeout = null;
                    cloud_sock.end();
                }, 10000);  
            }
            return;
        }

        // Build echo request
        let echoRequest = {
            action: 'echo',
            apiToken: getApiToken(),
            cloudApiVersion: '1.0',
            merchantId: getMID(),
            requestId: getRequestId(),
            requestTimestamp: getDateTime()
        };

        console.info(
            '\x1b[32m',
            'Sending Echo Request: ' + new Date().toString() +
            '\n' + JSON.stringify(echoRequest, null, 2)
        );

        cloud_sock.gotEchoNoResponse = 0;
        let sendbuf = twoBytesHeaderAppender(echoRequest);
        cloud_sock.write(sendbuf);  //send echo

    }, 30000); // every 30s
}

function stopEchoInterval(cloud_sock) {
    if (cloud_sock.echoInterval) {
        clearInterval(cloud_sock.echoInterval);
        cloud_sock.echoInterval = null;
    }
    if (cloud_sock.echoTimeout) {
        clearTimeout(cloud_sock.echoTimeout);
        cloud_sock.echoTimeout = null;
    }
}
// build gettables response
function getTables(request) {

    let requestId = request.requestId;
    let session = request.session;
    let requestServerId = request.data.server.serverId;
    let requestTrack2;
    let tId = request.terminalId;
    let mId = request.merchantId;
    let response = {};
    response = {
        'terminalId': tId,
        'merchantId': mId,
        'configCode': getCfgCode(),
        'requestId': requestId,
        'responseTimestamp': getDateTime(),
        'session': session
    }
    if (request.data.server.serverId != undefined)
        requestServerId = request.data.server.serverId;

    if (request.data.server.trackData != undefined)
        requestTrack2 = request.data.server.trackData.track2;

    if (requestServerId === undefined && requestTrack2 === undefined) {
        response.status = "603";
        response.statusDesc = errCodesMsgsMap[response.status];
        console.info("unable to determine the serverId", request.data.server.serverId);

        return response;
    }

    //for example, your serverId = 1234, and there are 3 tables for this serverId 
    if (requestServerId == '1234') {
        response = {
            ...response,
            'data': {
                'tables': [
                    {
                        'tableId': '00',
                        'tableName': '0020',
                        'tableTotalAmount': 15000,
                        'tableRemainingAmount': 15000
                    },
                    {
                        'tableId': '01',
                        'tableName': 'Alphabets',
                        'tableTotalAmount': 9500,
                        'tableRemainingAmount': 9500
                    },
                    {
                        'tableId': '02',
                        'tableName': 'DiningRoom7',
                        'tableTotalAmount': 24000,
                        'tableRemainingAmount': 24000
                    }
                ]
            },
            'status': '200',
            'statusDesc': 'OK'
        }
    } else {
        response.status = '614';
        response.statusDesc = errCodesMsgsMap[response.status];
    }
    return response;
}
// build gettable response
function getTable(request) {
    let requestId = request.requestId;
    let session = request.session;
    let requestServerId = request.data.server.serverId;
    let tableId;
    let tId = request.terminalId;
    let mId = request.merchantId;
    let response = {};

    response = {
        'terminalId': tId,
        'merchantId': mId,
        'configCode': getCfgCode(),
        'requestId': requestId,
        'responseTimestamp': getDateTime(),
        'session': session
    }
    if (request.data.server.serverId != undefined) {
        requestServerId = request.data.server.serverId;
    } else {
        response.status = "603";
        response.statusDesc = errCodesMsgsMap[response.status];
        console.info("unable to determine the serverId", request.data.server.serverId);

        return response;
    }
    if (request.data.tableId != undefined) {
        tableId = request.data.tableId;
    } else {
        response.status = "606";
        response.statusDesc = errCodesMsgsMap[response.status];
        return response;
    }

    //for example, your serverId = 1234, and there are 3 tables for this serverId 
    if (requestServerId == '1234') {
        // in this sample code, response the same detail data for tableId '00' and '01'; it will response error code 615 for tableid '03'. 
        if ((tableId == '00') || (tableId == '01')) {
            response = {
                ...response,
                'data': {
                    'table': {
                        'masterCheck': {
                            'receipt': {
                                'taxes': [],
                                'discounts': [],
                                'lineItems': []
                            },
                            'checkId': '1',
                            'checkName': 'Full Table',
                            'totalAmount': 15000,
                            'preTaxAmount': 14000,
                            'remainingAmount': 15000
                        },
                        'checks': [],
                        'tableId': '00',
                        'tableName': '0020',
                        'tableTotalAmount': 15000,
                        'tableRemainingAmount': 15000,
                        'splitMethod': 1
                    }
                },
                'status': '200',
                'statusDesc': 'OK'
            }
        }
        else {
            response.status = '615';
            response.statusDesc = errCodesMsgsMap[response.status];
        }

    } else {
        response.status = '614';
        response.statusDesc = errCodesMsgsMap[response.status];
    }
    return response;
}
//process payment, update payment information in your database 
function processPayment(request) {
    let requestId = request.requestId;
    let session = request.session;
    let requestServerId = request.data.server.serverId;
    let tableId, checkId;
    let tId = request.terminalId;
    let mId = request.merchantId;
    let response = {};

    response = {
        'terminalId': tId,
        'merchantId': mId,
        'configCode': getCfgCode(),
        'requestId': requestId,
        'responseTimestamp': getDateTime(),
        'session': session
    }
    if (request.data.server.serverId != undefined) {
        requestServerId = request.data.server.serverId;
    } else {
        response.status = "603";
        response.statusDesc = errCodesMsgsMap[response.status];
        console.info("unable to determine the serverId", request.data.server.serverId);

        return response;
    }
    if (request.data.check.tableId != undefined) {
        tableId = request.data.check.tableId;
    } else {
        response.status = "606";
        response.statusDesc = errCodesMsgsMap[response.status];
        return response;
    }
    if (request.data.check.checkId != undefined) {
        checkId = request.data.check.checkId;
    } else {
        response.status = "608";
        response.statusDesc = errCodesMsgsMap[response.status];
        return response;
    }
    if (request.data.payment != undefined) {
        //process payment object
    } else {
        response.status = "611";
        response.statusDesc = errCodesMsgsMap[response.status];
        return response;
    }
    // all amount should be your real amount.
    response = {
        ...response,
        'status': '200',
        'statusDesc': 'OK',
        'data': {
            'check': {
                'checkId': checkId,
                'checkName': 'checkName',
                'totalAmount': 15000,
                'preTaxAmount': 14000,
                'remainingAmount': 10000
            },
            'table': {
                'tableId': tableId,
                'tableName': '0020',
                'tableTotalAmount': 15000,
                'tableRemainingAmount': 10000
            }
        }
    }
    return response;
}
let connectToRMSCloud = function (cloudSever, options) {

    console.info('connectToRMSCloud');
    // tls connecion to moneris RMS cloud
    cloud_sock = tls.connect(cloudSever, options, function () {
        console.info('connected to options: ', cloudSever.host, ' port: ', cloudSever.port);
        //authenticate request
        let authReq = {
            action: 'authenticate',
            apiToken: getApiToken(), // your apitoken
            cloudApiVersion: '1.0',
            merchantId: getMID(),
            requestId: getRequestId(),
            requestTimestamp: getDateTime()
        };
        console.info('send to cloud:\n ', JSON.stringify(authReq, null, 2));
        let sendbuf = twoBytesHeaderAppender(authReq);
        cloud_sock.write(sendbuf);

        cloud_sock.on('close', onClose);
        cloud_sock.on('data', onData);
        cloud_sock.on('error', onError);
        cloud_sock.on('timeout', onTimeout);
    });
}

let onClose = function () {
    //process if connection is closed.
    console.info('cloud onClose ', new Date().toString());
    stopEchoInterval(cloud_sock);
    
};


let onData = async function (dataWith2Bytes) {
    //
    let response = [], sendbuf = [];
    let [isErrored, data] = twoBytesHeaderTrimmer(dataWith2Bytes);  // only convert to JSON
    if (isErrored) {
        cloud_sock.end();
        return;
    }

    if (data.action == ActionType.echo) {
        console.info('\x1b[32m', ' rev echo:\n' + JSON.stringify(data, null, 2));
    } else {
        console.info('rev:\n' + JSON.stringify(data, null, 2));
    }
    let status = parseInt(data.status);
    switch (data.action) {
        case ActionType.authenticate:  //process authenticate action response
            let status = parseInt(data.status);
            if (status === 200) { // good status
                console.info('Authenticate response OK, SetInterval for sending Echo Request');
                // set echo interval every 30 sec
                startEchoInterval(cloud_sock);
             
            } else {
                console.info('\x1b[31m', 'Authenticate response failed: ' + data.status + ' ' + 'Desc: ', data.statusDesc);
                cloud_sock.end();

            }
            break;
        case ActionType.echo:  //process authenticate action response

            if (cloud_sock.echoTimeout != undefined) {

                clearTimeout(cloud_sock.echoTimeout);
            }
            cloud_sock.gotEchoNoResponse = 1;
            break;
        case ActionType.getTables:  //process getTables action request

            response = getTables(data);
            sendbuf = twoBytesHeaderAppender(response);
            cloud_sock.write(sendbuf);
            console.info('response on getTables:' + new Date().toString() + '\n' + JSON.stringify(response, null, 2));
            break;
        case ActionType.getTable://process getTable action request

            response = getTable(data);
            sendbuf = twoBytesHeaderAppender(response);
            cloud_sock.write(sendbuf);
            console.info('response on getTables:' + new Date().toString() + '\n' + JSON.stringify(response, null, 2));
            break;
        case ActionType.applyPayment: //process payment action request
            response = processPayment(data);
            sendbuf = twoBytesHeaderAppender(response);
            cloud_sock.write(sendbuf);
            console.info('response on getTables:' + new Date().toString() + '\n' + JSON.stringify(response, null, 2));
            break;
        default:

            response = {
                'terminalId': data.terminalId,
                'merchantId': data.merchantId,
                'configCode': getCfgCode(),
                'requestId': data.requestId,
                'responseTimestamp': getDateTime(),
                'session': data.session,
                'status': '218',
                'statusDesc': errCodesMsgsMap['218']
            }
            sendbuf = twoBytesHeaderAppender(response);
            cloud_sock.write(sendbuf);
            console.info('unkonwn action: \n', JSON.stringify(response, null, 2));
            break;
    }
};

let onError = function (e) {
    console.info('cloud onError', e);
    cloud_sock.destroy();
 
};


let onTimeout = function () {
    console.info('onTimeout, end session');
    cloud_sock.end();
 
};


//add 2 bytes of message length at front
const twoBytesHeaderAppender = function (dataObject) {

    let bufContent;

    bufContent = Buffer.from(JSON.stringify(dataObject), 'utf8');

    let bufTwoBytesHeader = Buffer.alloc(2);
    bufTwoBytesHeader.writeUInt16BE(bufContent.length, 0);

    let buf = Buffer.concat([bufTwoBytesHeader, bufContent]);

    return buf;
};

//get message from Moneris cloud
const twoBytesHeaderTrimmer = function (data) {

    let isErrored = true;
    let message = '';
    if (data.length <= 2) {

        return [isErrored, message];
    }

    let dataLen = data.readUInt16BE(0);
    if (dataLen !== data.length - 2) {
        console.log(dataLen);
        console.log(data.toString());

        return [isErrored, message];
    }

    try {
        message = JSON.parse(data.slice(2).toString());
        isErrored = false;

        return [isErrored, message];
    } catch (e) {
        console.error('JSON parse error', e);
        console.error('JSON onParseError', data.toString());

        return [isErrored, message];
    }
};


/***************************************************************************
 *                              Connect to RMS Cloud                       *
 ***************************************************************************/
connectToRMSCloud(cloudSever, options);
/*************************************************************************
 *                       Socket event handler setup                      *
 *************************************************************************/