For terminal integrations, the
cloud integration strategy is used. When the cloud is used, a POS interacts with the terminal cloud, which communicates with a terminal using a persistent TCP channel. This channel remains open as long as the terminal is active and no maintenance procedures are carried out. The terminal cloud is a part of the gateway, and for all practical purposes the cloud and the gateway can be viewed as the same thing. They are treated separately in the documentation to simply demonstrate the concept in the more clear way.
Cloud integration works in the following way: a terminal connects to the gateway and holds a persistent channel. POS can then send the information to the gateway indicating, which terminal is to receive API calls. Every transaction request is being processed for about 5 seconds. The gateway routes the API calls to the appropriate terminal using the persistent channel that the terminal previously opened, and the responses are returned in the same way. The speed of transaction processing depends on the Internet speed and stability. Usually, terminals support speed of 10-100 MB.
See this
diagram to review the structure of the cloud integration. See this
diagram to review transaction processing flow for cloud.
Note: Typically, a password for a service user that works with real-time API consists of 32 characters. However, for terminal API, length of a service user password equals to 20 characters as another 12 characters are used by a terminal and are added automatically when processing a transaction.
Cloud Processing Configuration
In the cloud integration, a terminal and POS system interact via the cloud server which is a part of the gateway. POS exchanges API calls with the cloud while the cloud forwards API calls to the terminal, and sends the response back to the POS. Given this approach, POS system has to remain connected to the gateway for a duration of the entire transaction, which may take more time than regular card not present transactions. It is necessary to take into account the time that cardholder is going to spend to insert the card and enter the PIN, when needed, into the terminal. Therefore, care must be taken from the POS line to allow connection to the gateway on
card present transactions directed to the terminal
to remain open for up to three minutes. This is emphasized because the default timeout set by most of the programming languages in similar circumstances is under one minute, which is not going to be sufficient most likely for this type of transactions.
Note that it is important to increase timeout for communication with the cloud only. For cases when a large number of terminals is used, system settings should be configured in a way allowing to hold a large number of open connections simultaneously – it is recommended to use
non-blocking I/O (NIO), which requires fewer resources than blocking I/O. NIO is used to open a large number of communication channels simultaneously and manage them using one execution thread. If blocking I/O is used, it is required to open a separate execution thread for each channel.
For cloud integration, ports
443 and
8445 are required to be open for incoming and outgoing requests between the cloud server and a local network, to which a terminal is connected. Otherwise, if a facility network blocks these ports, the cloud will not operate. To verify that communications between a local network and the cloud server are allowed, check their IP addresses and associated ports. To retrieve an IP address of the cloud server, please, contact support. See this
diagram for a visual representation of the data exchange between a terminal and the cloud server.
Below you can review Java and C# code samples of cloud communication implementation.
Java Sample
public static void main (String[] argc) throws IOException
{
String response = doPostRequest ("https://[server-name]/terminals/xurl",
"requestType=sale" +
"&userName=myUser" +
"&password=myPassword" +
"&merchantAccountCode=2001" +
"&terminalCode=001" +
"&transactionIndustryType=RE" +
"&amount=500");
}
//simple implementation of HTTPs based communication
public static String doPostRequest(String cloudAddress, String data) throws IOException{
HttpURLConnection conn = null;
InputStream stream = null;
URL urlLink = new URL(cloudAddress);
OutputStreamWriter writer = null;
conn = (HttpURLConnection)urlLink.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setConnectTimeout(10000);
conn.setReadTimeout(60000);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestMethod("POST");
writer = new OutputStreamWriter(conn.getOutputStream());
writer.write(data);
writer.flush();
writer.close();
if (conn.getResponseCode() = = HttpURLConnection.HTTP_OK) {
stream = conn.getInputStream();
} else {
stream = conn.getErrorStream();
}
if (stream = = null){
System.out.println("Response code is " + conn.getResponseCode());
return "";
}
return stream2String(stream);
}
private static String stream2String(InputStream is) throws IOException{
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = br.readLine())!= null){
sb.append(line);
}
return sb.toString();
}
C# Sample
public static void Main (string[] argc)
{
string response = DoPostRequest ("https://[server-name]/terminals/xurl",
"requestType=sale" +
"&userName=myUser" +
"&password=myPassword" +
"&merchantAccountCode=2001" +
"&terminalCode=001" +
"&transactionIndustryType=RE" +
"&amount=500");
}
//simple implementation of HTTPs based communication
public static string DoPostRequest(string cloudAddress, string postData)
{
var data = Encoding.ASCII.GetBytes(postData);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(cloudAddress);
request.Method = "POST";
request.Timeout = 60000;
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
if (reader != null) { reader.Close(); reader.Dispose(); }
if (dataStream != null) { dataStream.Close(); dataStream.Dispose(); }
if (response != null) { response.Close(); }
return responseFromServer;
}