Interact with Gateway

#Overview

ZOLOZ SaaS API is language independent, which means the customer could integrate the API with any programmatic language. However, the customer needs to fully understand ZOLOZ gateway protocol, properly create the request and handle the response. If the customer's project is written in Java, the customer could utilize an existing API SDK provided by ZOLOZ to integrate the API with ease, or else the customer could attempt to make his own implementation.


In this chapter, we will firstly introduce how to utilize ZOLOZ API SDK, and then introduce how to use ZOLOZ help script to interact with ZOLOZ gateway, and finally introduce the advanced usage of ZOLOZ help script targeting on assisting the customer to validate his own implementation of the gateway protocol.

#Utilize ZOLOZ API SDK

#Integrate

To utilize ZOLOZ API SDK, the customer only needs to introduce the library into the maven project by adding following dependency in the main POM file:

copy
<dependency>
    <groupId>com.zoloz.api.sdk</groupId>
    <artifactId>zoloz-api-sdk</artifactId>
    <version>0.1.0</version>
</dependency>

#Usage

copy
// initialize OpenApiClient
String clientId = "<Client ID>";
String zolozPublicKey = "<ZOLOZ's public key content encoded in base64>";
String merchantPrivateKey = "<The merchant's private key content encoded in base64>";

OpenApiClient client = new OpenApiClient();  // construct with signature and encryption by default
client.setHostUrl("https://sg-production-api.zoloz.com");
client.setClientId(clientId);
client.setMerchantPrivateKey(merchantPrivateKey);
client.setOpenApiPublicKey(zolozPublicKey);
//client.setSigned(false);     // signature (of response) validation can be turned off
//client.setEncrypted(false);  // encryption can be turned off

String response = client.callOpenApi(
    "v1.zoloz.authentication.test", 
    "{\"title\": \"hello\", \"description\": \"just for demonstration.\"}"
    );

#Get the source code

ZOLOZ API SDK has been open sourced on Github, please check the source code here.

#PHP sample code

we also provide a php sample code here.

#Utilize ZOLOZ Helper Script

#Get the script

The helper script has been open sourced on Github, please check the source code here.

#Usage

copy
./zoloz.sh \
  -c 2188000123456789 \
  -P merchant_private_key.pem \
  -K 'MIIBIj...QIDAQAB' \
  -a /api/v1/zoloz/authentication/test \
  -d '{\n  "title": "hello",\n  "description": "just for demonstration."\n}'
  • 2188000123456789 is a dummy client Id, the customer should replace with his own one acquired from ZOLOZ portal.
  • merchant_private_key.pem is the private key generated at the customer's side, of which the corresponding public key has been registered in ZOLOZ portal.
  • 'MIIBIj...QIDAQAB' is the dummy content of the ZOLOZ public key, the customer should replace with his own one acquired from ZOLOZ portal.

Other control options:

  • -e : disable encryption
  • -i : skip response signature validation

#Own's Implementation Validation

In case the customer would like to implement the gateway protocol by his own, it's important for the customer to be capable of validating his own's implementation.


The helper script mentioned in previous section could help the customer a lot for validation purpose by adding some other options:

  • -v  or -vv : this will make the script more verbose and output much more intermediate data for validation.
  • -t <request time> : this will make the request adopt specified time instead of invoking time.
  • -k <AES128 key> : this will make the request adopt specified AES128 key to encrypt request content instead of a randomly generated one.


Here's an live example of API call:

8C8097C1-574E-4460-9EB2-7A54C9021A64.png


The customer could validate as following steps:

#1 Invoke the script to call the API

copy
./zoloz.sh \
  -c 2**************4 \
  -P merchant_private_key.pem \
  -K 'MIIBIj...QIDAQAB' \
  -a /api/v1/zoloz/authentication/test \
  -d '{
  "title": "hello",
  "description": "This is just a demonstration."
}' \
  -vv \
  -k 31313131313131313131313131313131 \
  -t 2020-12-01T00:00:00+0800

Here list some important options:

  • Enable verbose mode by adding -vv  option
  • Specify the AES128 key used to encrypt the request content with -k option (in the example we assume that the randomly generated AES128 key is 0x31313131313131313131313131313131)
  • Specify the request time directly with -t option (in the example we assume that the desired time is 2020-12-01 00:00:00 Singapore time)


#2. Validate request encryption

Confirm the final request content (“request body“) is the same with that of the customer's implementation:

copy
> request data length: 75
>> request data: '{\n  "title": "hello",\n  "description": "This is just a demonstration."\n}'
>
> encryption: 1
> aes128 key: 0x31313131313131313131313131313131
> encrypted aes128 key: DcTqQNe9wc8HZByHRKZBM5HNAypDAWvHD8ugVxiQBdjosM4qzGPtI/sj58V48I0hYK/NLM3J1BcWf+TEXQzz7WkKl1+IVyF+2iYxe8Dx6UJeLNXFsHMKYWNiIdo4cKzkBL4lBEdJhZJwZtkYePq9dNAtXXWxBAsSDFDLejH1sTfBdpVUvGz0xUBZHeisNDS4Z1a/Em+RUtTZo7RqdGlBiUrSwVTOCcsrbaVk+LSP/GpVzbxMZU+FQ38/dvvHf6M7LlreRdyVIz4Rcz74sLOoEuYSg9ccTwp5modp04WRkCFYGI4FyMfZzam/hUWwe194LdUFpR+Dqp4GIiKVY5Vgjg==
> urlencoded encrypted aes128 key: DcTqQNe9wc8HZByHRKZBM5HNAypDAWvHD8ugVxiQBdjosM4qzGPtI%2fsj58V48I0hYK%2fNLM3J1BcWf%2bTEXQzz7WkKl1%2bIVyF%2b2iYxe8Dx6UJeLNXFsHMKYWNiIdo4cKzkBL4lBEdJhZJwZtkYePq9dNAtXXWxBAsSDFDLejH1sTfBdpVUvGz0xUBZHeisNDS4Z1a%2fEm%2bRUtTZo7RqdGlBiUrSwVTOCcsrbaVk%2bLSP%2fGpVzbxMZU%2bFQ38%2fdvvHf6M7LlreRdyVIz4Rcz74sLOoEuYSg9ccTwp5modp04WRkCFYGI4FyMfZzam%2fhUWwe194LdUFpR%2bDqp4GIiKVY5Vgjg%3d%3d
>
> request body length: 108
>> request body: 'Ve/sPNvLd1pDkl6gZURFrHS0mtzz2a0aCt927jgTarQbCBZYn2ikk8nrT5ymQ7YgqrqaOs2qnQW/3G/uVN+n6XJn5jVHTUfTTGJki/Gnqvs='

NOTE:

Most implementations of RSA encryption add random information to avoid possible attacks, so it is as expected that the customer's implementation produces different result for AES128 key encryption. However, the request content encryption is verifiable.


#3. Validate request signature

Confirm the request signature (urlencoded request signature“) is the same with that of the customer's implementation:

copy
>> request content to be signed: 'POST /api/v1/zoloz/authentication/test\n2188423368528034.2020-12-23T16:00:07+0800.Ve/sPNvLd1pDkl6gZURFrHS0mtzz2a0aCt927jgTarQbCBZYn2ikk8nrT5ymQ7YgqrqaOs2qnQW/3G/uVN+n6XJn5jVHTUfTTGJki/Gnqvs='
> request signature: DXFMXcAw9+tx48c47ilhYY0yTBst0u4f2jLMBJl2H9dfPYiOwXH6EWTIyijGPUPVmWFK9pVx8fbUBeS2eIlRluxk+gKA/SuOIMg0VmQAyglIZjJKT7ecdYAqs90f76Pp3MM9LEyAeINlajd6lKyjJwN9YiNoRMoD1g78w7OOw8MbPY52hag0RoV1UGydC8ifK24amyu6+WVVy6XuLgcL1n/CaSk1urIUSFAm9Mq1xQ/ndz9VRHDLspbyfEt/2eML5vWoTyYxZxm9KYyMBjTVmZ9R0mbQMpFPXC0LA89PR8aqv6pCyoTpQ5c5ECrVhgIokdYs5Uf05P0APeShRar2/g==
> urlencoded request signature: DXFMXcAw9%2btx48c47ilhYY0yTBst0u4f2jLMBJl2H9dfPYiOwXH6EWTIyijGPUPVmWFK9pVx8fbUBeS2eIlRluxk%2bgKA%2fSuOIMg0VmQAyglIZjJKT7ecdYAqs90f76Pp3MM9LEyAeINlajd6lKyjJwN9YiNoRMoD1g78w7OOw8MbPY52hag0RoV1UGydC8ifK24amyu6%2bWVVy6XuLgcL1n%2fCaSk1urIUSFAm9Mq1xQ%2fndz9VRHDLspbyfEt%2f2eML5vWoTyYxZxm9KYyMBjTVmZ9R0mbQMpFPXC0LA89PR8aqv6pCyoTpQ5c5ECrVhgIokdYs5Uf05P0APeShRar2%2fg%3d%3d


#4. Validate response signature

Confirm the signature (response signature“) could pass the signature validation of the customer's implementation against the target content (response content to be verified“):

copy
> response signature: OPiRd8jwCpP8M/Z+oNYjJLUU5zWd5XTk1XFQwX7+00AvIsAJpnP0YqgBfDrvlGuic38m164wAQUqKbFmSe6tNUFTmA+JZxnrwGSZmEbBuRzbB44h0Srgq+W6rC8oqntqjEWDVkdWzaayij5E/2ZAvsKKrTHPBjmECQ+jb78kwRo+jOlZ6rIOqSmKo2UL7XKsYhChKwrUe7nbwpBIg+fBEqMglCDCbMsSSsuavMpco1cwBtAXaZyPRmsqA27bTo9TSij65ovbeOxdZmBZqLXc7jiFKYFOJdLREXC022gLYALuUeP/PWecargIduHg5D+2+MXKiWYIhBZ7RYQe7Qtnew==
> response time: 2020-12-23T08:01:04+0000
>> response content to be verified: 'POST /api/v1/zoloz/authentication/test\n2188423368528034.2020-12-23T08:01:04+0000.Ve/sPNvLd1pDkl6gZURFrHS0mtzz2a0aCt927jgTarQbCBZYn2ikk8nrT5ymQ7YgqrqaOs2qnQW/3G/uVN+n6XJn5jVHTUfTTGJki/Gnqvs='
> response signature verification result: 'Verified OK'


#5. Validate response decryption

Confirm the customer's implementation could decrypt the encrypted AES128 key (response encrypted symmetric key“) to the same AES128 key (response symmetric key“), and could decrypt the encrypted response content (response body“) to the same plain content (response content“).

copy
>> response body: 'Ve/sPNvLd1pDkl6gZURFrHS0mtzz2a0aCt927jgTarQbCBZYn2ikk8nrT5ymQ7YgqrqaOs2qnQW/3G/uVN+n6XJn5jVHTUfTTGJki/Gnqvs='

> response encrypted symmetric key: I6dJGifO9pwTN26uoeET/T/aF8sDVBjnZY0dLaQu5WVbIbZTHEabGg8810N1tJGvbYtWjcJmM1XwKlOieLtVMElPgEpfQ3H3hrFotBpJM5qkYRaUKnJIQpWJSm5fPP4Pr+Lye2M+uVjkieNvTGe36OhBWOfxuhfo70x4jMENXHj2QuEP0JLu0peQBaoMKh/0C47fCQgijBrjcG0ON3eUe4jTvGQ5t00dFKhVmOnnHrP4zOFA6nfgGV4+T702fGxgIoq2CByT+hEWqvVXsEgZWzLse0RDcBjZ/ValRAxQYNuKP8ZzUNGiUt5GlyRmMi4aB69oFTx65Ey//5UXAxFvpg==
> response symmetric key: 0x31313131313131313131313131313131
> response content length: 72
>> response content: {
>>   "title": "hello",
>>   "description": "This is just a demonstration."
>> }