v2.x


The following examples are unique for branch 2.x of the API. UDP broadcast remains unchanged.

Authentication link

Node JS link

Node v16.14.0


const crypto = require('crypto')
const http = require('http')
 
function makeAuthorizationHeader(timestamp, hash) {
    return `Samport-Keyed-Hash-v1 ${timestamp} ${hash}`
}
 
function generateRequestHash(secretKey, timestamp, httpMethod, httpPath, httpContent) {
    const hashInput = `${secretKey}\n${timestamp}\n${httpMethod}\n${httpPath}\n${httpContent}\n${secretKey}`
    return crypto.createHash('sha256').update(hashInput, 'utf8').digest('base64')
}
 
function generateResponseHash(secretKey, timestamp, httpMethod, httpPath, httpStatus, httpContent) {
    const hashInput = `${secretKey}\n${timestamp}\n${httpMethod}\n${httpPath}\n${httpStatus}\n${httpContent}\n${secretKey}`
    console.info('Hash input: ' + hashInput)
    return crypto.createHash('sha256').update(hashInput, 'utf8').digest('base64')
}
 
const terminalIp = '12.232.12.31'
const terminalPort = 8080
const integrationKey = 'ABCDABCDABCDABCD'
 
const secretKey = 'HelloWorld'
const timestamp = new Date().toISOString()
const httpVerb = 'POST'
const httpPath = '/api/v2/Payments'
const content = JSON.stringify({
    "amounts": {
        "currencySymbol": "SEK",
        "base": 10050
    }
})
 
const options = {
    host: terminalIp,
    port: terminalPort,
    path: httpPath,
    method: httpVerb,
    headers: {
        'Integration-Key': integrationKey,
        'Content-Type': 'application/json',
        'Authorization': makeAuthorizationHeader(timestamp, generateRequestHash(secretKey, timestamp, httpVerb, httpPath, content))
    }
}

const req = http.request(options, function(response) {
    let data = ""
    response.on('data', function(chunk) {
        data += chunk
    })
    response.on('end', function() {
        const serverAuthorization = response.headers['server-authorization']
        const serverTimestamp = serverAuthorization.split(' ')[1]
        const serverHash = serverAuthorization.split(' ')[2]
        const correctHash = generateResponseHash(secretKey, serverTimestamp, httpVerb, httpPath, response.statusCode, data)
        console.info('Status: ', response.statusCode)
        console.info('Headers: ', response.headers)
        console.info('Content: ' + data)
        console.info('Server timestamp: ' + serverTimestamp)
        console.info('Server hash: ' + serverHash)
        console.info('Correct hash: ' + correctHash)
        if (serverHash === correctHash) {
            console.info('Response verified')
        } else {
            console.info('Response invalid')
        }
    })
})

req.write(content)
req.end()
 

Kotlin link

Kotlin 1.6.21


import com.google.gson.Gson
import java.net.HttpURLConnection
import java.net.URL
import java.nio.charset.Charset
import java.security.MessageDigest
import java.time.Instant
import java.util.*

const val terminalIp = "12.232.12.31"
const val terminalPort = 8080
const val integrationKey = "2870736033170FD5"
const val secretKey = "HelloWorld"
const val httpVerb = "POST"
const val httpPath = "/api/v2/Payments"
val timestamp = Instant.now().toString()

fun main() {
    sendRequest()
}

fun sendRequest() {
    val content = mapOf(
        "amounts" to mapOf(
            "currencySymbol" to "SEK",
            "base" to 10050
        )
    )
    
    val jsonContent = Gson().toJson(content)

    val url = URL("http://$terminalIp:$terminalPort$httpPath")
    val urlConnection = url.openConnection() as HttpURLConnection
    urlConnection.setRequestProperty("Integration-Key", integrationKey)
    urlConnection.setRequestProperty("Content-Type", "application/json")
    urlConnection.setRequestProperty("Authorization", makeAuthorizationHeader(timestamp,generateRequestHash(secretKey,timestamp,httpVerb,httpPath, jsonContent)))

    urlConnection.requestMethod = httpVerb
    urlConnection.doOutput = true
    
    urlConnection.outputStream.use { it.write(jsonContent.toByteArray(Charset.defaultCharset())) }
    
    val responseCode = urlConnection.responseCode
    println("Response Code: $responseCode")

    val serverAuthorization = urlConnection.getHeaderField("server-authorization")
    
    val serverAuthorizationSplit = serverAuthorization.split(" ")
    val serverTimestamp = serverAuthorizationSplit[1]
    val responseJson = urlConnection.inputStream.bufferedReader().use { it.readText() }
    val correctHash = generateResponseHash(secretKey, serverTimestamp, httpVerb, httpPath, responseCode.toString(), responseJson)
    val serverHash  = serverAuthorizationSplit[2]

    println(
        "Parameters:\n " +
                "SecretKey: $secretKey\n " +
                "ServerTimestamp $serverTimestamp\n " +
                "Httpverb: $httpVerb\n " +
                "HttpPath: $httpPath\n " +
                "Statuscode: $responseCode\n " +
                "JSON: $responseJson\n\n " +
                "CorrectHash: $correctHash\n"
    )

    if (serverHash == correctHash)
    {
        println("Response verified");
    }
    else
    {
        println("Response invalid");
    }
    println("*".repeat(80))
}

fun makeAuthorizationHeader(timestamp: String, hash: String): String {
    return "Samport-Keyed-Hash-v1 $timestamp $hash"
}

fun generateRequestHash(secretKey: String, timestamp: String, httpMethod: String, httpPath: String, httpContent: String): String {
    val hashInput = "$secretKey\n$timestamp\n$httpMethod\n$httpPath\n$httpContent\n$secretKey"
    val bytes = hashInput.toByteArray()
    val hash = MessageDigest.getInstance("SHA-256").digest(bytes)
    return Base64.getEncoder().encodeToString(hash)
}

fun generateResponseHash(secretKey: String, timestamp: String, httpMethod: String, httpPath: String, httpStatus: String, httpContent: String): String {
    val hashInput = "$secretKey\n$timestamp\n$httpMethod\n$httpPath\n$httpStatus\n$httpContent\n$secretKey"
    val bytes = hashInput.toByteArray()
    val hash = MessageDigest.getInstance("SHA-256").digest(bytes)
    return Base64.getEncoder().encodeToString(hash)
}
 

C# link

.NET 7


using System.Security.Cryptography;
using System.Text;
using System.Globalization;
using System.Net;
using Newtonsoft.Json;
using System.Net.Http;
using System;

private const string terminalIp = "12.232.12.31";
private const int terminalPort = 8080;
private const string integrationKey = "2870736033170FD5";
private const string secretKey = "HelloWorld";
private const string httpVerb = "POST";
private const string httpPath = "/api/v2/Payments";
private static string timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture);

public async Task SendRequest()
{
    var content = new
    {
        amounts = new
        {
            currencySymbol = "SEK",
            @base = 10050
        }
    };

    var jsonContent = JsonConvert.SerializeObject(content);

    var headers = new WebHeaderCollection
{
    {"Integration-Key", integrationKey },
    {"Content-Type", "application/json" },
    {"Authorization", MakeAuthorizationHeader(timestamp, RequestHash(secretKey, timestamp, httpVerb, httpPath, jsonContent))}
};

    string url = $"http://12.232.12.31:8080/api/v2/Payments";

    using (var client = new HttpClient())
    {
        var request = new HttpRequestMessage
        {
            RequestUri = new Uri(url),
            Method = HttpMethod.Post,
            Content = new StringContent(jsonContent, Encoding.UTF8, "application/json")
        };

        foreach (string key in headers.AllKeys)
        {
            request.Headers.TryAddWithoutValidation(key, headers[key]);
        }

        var response = client.SendAsync(request).Result;

        Console.WriteLine("### RESPONSE ###");

        if (response.Headers.Contains("server-authorization"))
        {
            string serverAuthorization = response.Headers.GetValues("server-authorization").First();

            string[] serverAuthorizationSplit = serverAuthorization.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            string serverTimestamp = serverAuthorizationSplit[1];
            string serverHash = serverAuthorizationSplit[2];

            string responseJson = await response.Content.ReadAsStringAsync();
            string correctHash = ResponseHash(secretKey, serverTimestamp, httpVerb, httpPath, ((int)response.StatusCode).ToString(), responseJson);

            Console.WriteLine($"Parameters:\n " +
                $"SecretKey: {secretKey}\n " +
                $"ServerTimestamp {serverTimestamp}\n " +
                $"Httpverb: {httpVerb}\n " +
                $"HttpPath: {httpPath}\n " +
                $"Statuscode: {response.StatusCode}\n " +
                $"JSON: {responseJson}\n\n " +
                $"ServerHash: {serverHash} \n " +
                $"CorrectHash: {correctHash}\n");



            if (serverHash == correctHash)
            {
                Console.WriteLine("Response verified");
            }
            else
            {
                Console.WriteLine("Response invalid");
            }
        }
        else
        {
            Console.WriteLine("Auth header is not present");
        }
        Console.WriteLine(new string('*', 80));
    }

    /*
      * Combining the secretKey and parameters to create the header
      * The spaces between the elements are necessary.
      */
    static string MakeAuthorizationHeader(string timestamp, string hash)
    {
        return $"Samport-Keyed-Hash-v1 {timestamp} {hash}";
    }

    /*
      * Combine the parameters to create the hashInput
      * Create a byte array of the input
      * Hash the byte array
      * Base64 convert the hash
      */
    static string RequestHash(string secretKey, string timestamp, string httpMethod, string httpPath, string httpContent)
    {
        string hashInput = $"{secretKey}\n{timestamp}\n{httpMethod}\n{httpPath}\n{httpContent}\n{secretKey}";
        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(hashInput);
        byte[] hash = SHA256.HashData(bytes);
        return Convert.ToBase64String(hash);
    }

    static string ResponseHash(string secretKey, string timestamp, string httpMethod, string httpPath, string httpStatus, string httpContent)
    {
        string hashInput = $"{secretKey}\n{timestamp}\n{httpMethod}\n{httpPath}\n{httpStatus}\n{httpContent}\n{secretKey}";
        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(hashInput);
        byte[] hash = SHA256.HashData(bytes);
        return Convert.ToBase64String(hash);
    }
}
 

Python link

Python 3.11.5 and requests 2.31.0

 
import sys
import requests
import json
import base64
from hashlib import sha256
from datetime import datetime, timezone

def generateRequestHash(secretKey, timestamp, httpVerb, httpPath, httpContent):
  # secretKey is added both in the beginning and the end to combat known sha256 vulnerability
  hashInput = f"{secretKey}\n{timestamp}\n{httpVerb}\n{httpPath}\n{httpContent}\n{secretKey}"
  return base64.b64encode(sha256(hashInput.encode("utf-8")).digest()).decode("utf-8")

def generateResponseHash(secretKey, timestamp, httpVerb, httpPath, httpStatus, httpContent):
  #Authenticating the response is not mandatory but recommended. Note that the response also includes httpStatus
  hashInput = f"{secretKey}\n{timestamp}\n{httpVerb}\n{httpPath}\n{httpStatus}\n{httpContent}\n{secretKey}"
  return base64.b64encode(sha256(hashInput.encode("utf-8")).digest()).decode("utf-8")

# Setup
host = "http://12.232.12.31:8080" # Make sure this IP/PORT matches your device.
integrationkey = "Your IntegrationKey" # Distributed by Worldline integration team
secretkey = "HelloWorld" # Distributed by Worldline integration team

#timestamp in UTC to not be affected by DST
timestamp = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
httpverb = "POST"
httppath = "/api/v2/Payments"

payload = json.dumps({
  'amounts': {
    'currencySymbol': 'SEK',
    'base': 10050
  }
})

authorizationheader = generateRequestHash(secretkey, timestamp, httpverb, httppath, payload)

headers = {'content-type': 'application/json; charset=utf-8',
       'Integration-Key': integrationkey,
       'User-Agent' : 'MyECR 1.0',
       'Content-Length': str(len(payload)),
       'Authorization' : f"Samport-Keyed-Hash-v1 {timestamp} {authorizationheader}"
       }

#print("\n #Request Headers:\n"+ json.dumps(headers))
try:
  req = requests.post(host + httppath, headers=headers, data=payload)

  print(req.status_code, req.reason)
  print(json.dumps(req.content.decode('utf-8'), indent=4))
except Exception as e:
  raise e


 

Read more