v1.x
Certificate management link
Handling the certificate is a bit different depending on what type of programming language you are using. Here are some code examples that can help you to get started quicker.
Every certificate management example is performing a /Payments of 100 SEK and the expected HTTP response is 200.
C# link
Version used: .NET 7
When using .Net we need to specify our own ServerCertificateCustomValidationCallback in order to supply our custom root certificate and to validate the commonname.
using System;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Security.Cryptography.X509Certificates;
public void SendHTTPRequest(HttpClient client){
client.DefaultRequestHeaders.Add("Integration-Key", "Your integration key");
//Starting the POST request
var syncRequest = new HttpRequestMessage("https://192.168.1.105/api/v1/Payments")
{
Content = new StringContent(JsonConvert.SerializeObject(
new
{
amounts = new
{
currencySymbol = "SEK",
@base = 100
},
sendReceipt = true,
},
Formatting.Indented, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}
), Encoding.UTF8, "application/json")
};
var response = client.Send(syncRequest);
var statuscode1 = response.StatusCode;
}
public HttpClientHandler CertHandler()
{
try
{
//generic common name
var commonName = "wl-samport-terminal-server-v1";
//path to cert
var path = "Certs\\ECR-REST.crt";
X509Certificate2 cert = new X509Certificate2(path);
var handler = new HttpClientHandler();
//specify our own ServerCertificateCustomValidationCallback in order to
//supply our custom root certificate and to validate the commonname
handler.ServerCertificateCustomValidationCallback = (requestMessage, certificate, chain, sslErrors) =>
{
if (certificate != null && chain != null)
{
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(cert);
// We can also return choose to simply "return true;" here, We dont have
// to confirm the commonName if we dont want to(doesn't decrease the amount of encryption)
return chain.Build(certificate) && certificate.Subject.Contains("CN=" + commonName);
}
return false;
};
return handler;
}
catch (Exception e)
{
Console.WriteLine("Exception: "+ e.Message);
}
return new HttpClientHandler();
}
Java link
Version used: 1.8.0_221
To create requests using Java we set a custom HostNameVerifier to accept ANY hostname.
public void Test1()throws IOException, NoSuchAlgorithmException, CertificateException, KeyStoreException, KeyManagementException {
//Load the certificate (path to certificate)
InputStream is = new FileInputStream("\\ECR-REST.crt");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate caCert = (X509Certificate)cf.generateCertificate(is);
//Setup a TrustmanagerFactory for the loaded certificate
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
ks.setCertificateEntry("caCert", caCert);
tmf.init(ks);
//Create SSLContext to apply TLS encryption
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
//Open Https Connection and assign a URL to our REST API.
// set Integration-Key
URL url = new URL("https://192.168.1.105/api/v1/Payments");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
urlConnection.setHostnameVerifier((hostname, session) -> true);
urlConnection.setRequestProperty("Integration-Key","Your integration key");
// Set GET or POST depeding on method you use
urlConnection.setRequestMethod("POST");
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
// You can of course create you own library to manage JSON in other ways
// But we chose to go with "org.json.JSONObject"
String jsonInputString = "";
try {
JSONObject amounts = new JSONObject();
amounts.put("currencySymbol", "SEK");
amounts.put("base", 100);
JSONObject json = new JSONObject();
json.put("amounts", amounts);
json.put("sendReceipt", true);
jsonInputString = json.toString();
}
catch (Exception e) {
System.out.println(e.getMessage());
}
// Sending
try(OutputStream os = urlConnection.getOutputStream()) {
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
// Receiving
BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
in.close();
int responseCode = urlConnection.getResponseCode();
System.out.println("Response code: "+responseCode);
}
Kotlin link
Version used: 1.4.20
Gradle: 6.8
When we create requests using Kotlin we set a custom HostNameVerifier to accept ANY hostname.
package org.me.mypackage
import java.io.BufferedReader
import java.io.FileInputStream
import java.io.InputStreamReader
import java.net.URL
import java.nio.charset.StandardCharsets
import java.security.KeyStore
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import javax.net.ssl.*
import org.json.JSONObject
fun Connect() {
//Upload the certificate and
val isStream = FileInputStream("C:\\certs\\ECR-REST.crt")
val cf = CertificateFactory.getInstance("X.509")
val caCert = cf.generateCertificate(isStream) as X509Certificate
//Create TrustManager for the loaded certificate and apply the default KeyStore type
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
val ks = KeyStore.getInstance(KeyStore.getDefaultType())
ks.load(null)
ks.setCertificateEntry("caCert", caCert)
tmf.init(ks)
//Create SSLContext and assign TLS as encryption
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, tmf.trustManagers, null)
//Give the HTTPS ConnectionClass an IP address(URL)
val url = URL("https://192.168.5.105/api/v1/Payments")
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.sslSocketFactory = sslContext.socketFactory
//Tell the HttpConnection to accept ALL hostnames
urlConnection.hostnameVerifier = HostnameVerifier { _: String?, _: SSLSession? -> true }
urlConnection.setRequestProperty("Integration-Key", "Your integration key"
urlConnection.setRequestProperty("Content-Type", "application/json")
// GET, POST Method chosen
urlConnection.requestMethod = "POST"
urlConnection.doInput = true
urlConnection.doOutput = true
// Create JSON data with the help of JSONObject library
var jsonInputString = ""
try {
val amounts = JSONObject()
amounts.put("currencySymbol", "SEK")
amounts.put("base", 10)
val json = JSONObject()
json.put("amounts", amounts)
json.put("sendReceipt", true)
jsonInputString = json.toString()
} catch (e: Exception) {
println(e.message)
}
//Send
urlConnection.outputStream.use { os ->
val input = jsonInputString.toByteArray(StandardCharsets.UTF_8)
os.write(input, 0, input.size)
}
//See results
val message = urlConnection.responseMessage
println("message: $message")
val inStream = BufferedReader(InputStreamReader(urlConnection.inputStream))
inStream.lines().forEach { println(it) }
inStream.close()
val responseCode = urlConnection.responseCode
println("Responsecode: $responseCode")
}
fun main() {
Connect()
}
C link
Version used: C90
In C we are removing the hostname verification by setting curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L) to false(0L).
#include <stdio.h>
#include <stdio.h>
#include <curl/curl.h>
int main(void) {
CURL* curl;
CURLcode res;
// Initialize libcurl
curl_global_init(CURL_GLOBAL_DEFAULT);
// Define the endpoint URL
const char* url = "https://192.168.1.105/api/v1/Payments"; // Replace with your actual endpoint URL
//Integration key and certificate path
const char* integration_key = "Integration-Key: Your integration key"; // Replace with your actual integration key
const char* certificate_path = "certs\\ECR-REST.crt"; // Replace with your actual certificate path
//JSON Body
char* json_data = "{\"amounts\":{\"base\": 100,\"currencySymbol\": \"SEK\",}}";
//Initialize a CURL handle
curl = curl_easy_init();
if (curl) {
//Set URL
curl_easy_setopt(curl, CURLOPT_URL, url);
//Set the integration key header + certificate
//remove verification of the hostname with "curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);"
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, integration_key);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_CAINFO, certificate_path);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
//Set the request type to POST and apply the json body
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data);
//Perform the request
res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
//Cleaning duty
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
}
//Cleaning duty
curl_global_cleanup();
return 0;
}
Node.js link
Version used: v16.14.0
When using Node.js we need to specify servername which specifies the hostname we expect to find in the certificate.
const request = require('request');
const fs = require('fs');
const body = `{
"amounts": {
"base": 100,
"currencySymbol": "SEK",
}
}`;
request({
uri:'https://192.168.1.105/api/v1/Payments/',
headers: {
'Integration-Key': 'Your integration key'
},
body:body,
method:'POST',
ca: [fs.readFileSync('certs\\ECR-REST.crt')],
servername: 'wl-samport-terminal-server-v1',
});
Python link
Version used: Python 3.11.5
This example works with “urllib3” version 2.0.6.
Setting assert_hostname to False disables the hostname verification because URL will not match certificate.
import urllib3
import json
# Make sure the IP-address matches your device
host = "192.168.1.105"
#
integrationkey = "YOUR INTEGRATION KEY"
# Path to the self-signed certificate file
cert_file = './ECR-REST.pem'
payload = {
'amounts': {
'currencySymbol': 'SEK',
'base': 100
}
}
json_payload = json.dumps(payload)
pool = urllib3.HTTPSConnectionPool(
host,
assert_hostname=False,
ca_certs=cert_file)
headers = {'content-type': 'application/json; charset=utf-8',
'Integration-Key': integrationkey,
'User-Agent' : 'MyECR 1.0',
'Content-Length': str(len(json_payload))
}
# Try sending a basic sync payment and print the response (response is only returned once you abort or finalize the payment in the terminal)
try:
req = pool.urlopen('POST', '/api/v1/Payments', body=json_payload, headers=headers)
print(req.status, req.reason)
print(req.data)
except Exception as e:
raise e
UDP Broadcast link
netstat -ano|findstr 8000 to find the PID of the process and then tskill <PID> to manually terminate it.
C# Broadcast example link
Version used: .NET 7
And here is an example of how the UDP broadcast can be written in C#
using System.Net;
using System.Net.Sockets;
using System.Text;
using Newtonsoft.Json;
using Formatting = Newtonsoft.Json.Formatting;
namespace Receiver
{
class Program
{
static void Main(string[] args)
{
int broadcastPort = 8000;
Console.WriteLine("UDP Broadcast Receiver (" + broadcastPort + ")");
UdpClient receiver = new UdpClient(broadcastPort);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
byte[] bytes = receiver.Receive(ref sender);
dynamic parsedJson = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(bytes));
Console.WriteLine("{0} - Message received from " + sender.Address.ToString() + ":" + sender.Port + ":", DateTime.Now.ToString("HH:mm:ss"));
Console.WriteLine(JsonConvert.SerializeObject(parsedJson, Formatting.Indented));
}
}
}
}
Node.js link
Version used: v16.14.0
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const port = 8000;
console.log(`UDP Broadcast Receiver (${port})`);
server.on('message', (msg, rinfo) => {
const parsedJson = JSON.parse(msg.toString('utf8'));
console.log(`${new Date().toISOString().slice(11, 19)} - Message received from ${rinfo.address}:${rinfo.port}:`);
console.log(JSON.stringify(parsedJson, null, 2));
});
server.bind(port);
Example broadcast link
The message from the terminal will look like this and will have all the information needed for you to configure your application.
"WORLDLINE_TERMINAL": {
"v0": {
"terminalId": "182837313011101003287575",
"identity": "47084495",
"ipAddress": "10.232.130.102",
"port": 443,
"protocolType": "EcrRestApi",
"protocolVersion": "1.0.0",
"commonName": "wl-samport-terminal-server-v1"
},
}