WebAPI integration

Technical questions relating to the iVeri WebService integration
Post Reply
Posts: 54
Joined: Thu Sep 17, 2015 3:29 pm

Wed Mar 30, 2016 3:07 pm

Thanks Stephen, not much of a PHP Developer myself but this will definitely help :D
Posts: 2
Joined: Mon Apr 25, 2016 3:48 pm

Mon Apr 25, 2016 5:57 pm

Hi Stephen,

I am building something similar in Ruby at the moment and I was/am having the exact same problems and questions. So thank you for pointing most of the stuff out in the first place!

I use the gem RestClient (similar to Guzzle) and rewrote the token algorithm. I tried to establish a successful connection to the merchant/authenticate endpoint.

The token is the same as in the Java-Implementation. I tried to do it like you did, but I only get 401 Unauthorized.

This is my test implementation:

Code: Select all

require 'date'
require 'digest'
require 'rest-client'
require 'awesome_print'

username = 'yyy'
usergroup = 'xxx'
password = 'ccc'

def generate_token url, timestamp, password
  password_digest = Digest::MD5.digest(password)

url = 'https://gateway.iveri.co.za/api/merchant/authenticate'
timestamp = DateTime.now.strftime("%Y%m%d%H%M%S%3N")

token = generate_token url, timestamp, password
auth = 'Basic usergroup="'+usergroup+'", username="'+username+'", timestamp="'+timestamp+'", token="'+token+'"'

@resource = RestClient::Resource.new( url )
@response = @resource.get( :Authorization => auth )
ap @response.body
Did you do something special to get the http authorization to work? Am I missing something?

I would much appreciate your help in this matter.


Stephen wrote:For any PHP developers who run into issues with authorisation in future - let me save you some time. I've managed to get this working correctly using guzzle and setting the authorization header manually instead of using the standard expected username and password params.

First, we need to declare some credentials somewhere - Following OOP standards:

Code: Select all

private $backoffice_username = 'dummy_username';
private $backoffice_usergroup = 'dummy_usergroup';
private $backoffice_password = 'dummy_password';

private $backoffice_gateway = 'https://gateway.iveri.co.za/api/';
Note: The gateway is not what was mentioned earlier. The above works as expected.

Then we need a function to generate the timestamp in the format '"yyyyMMddHHmmssfff' which is would look something like 20160330143402422 - Year, month, day, hour, minute, seconds and milliseconds.

Now, if we didn't require milliseconds, this would be as easy as:

Code: Select all

return date('YmdHis');
Unfortunately, PHP doesn't have an easy way to append the milliseconds to this date so we need to add a bit of additional code:

Code: Select all

private function getTimestamp() {
   $microtime = microtime(true);
   $microseconds = sprintf("%06d",($t - floor($t)) * 1000000);
   $date = new DateTime( date('YmdHis'.$microseconds, $microtime) );

   return $date->format("YmdHisu");
Next up, the token generation as mentioned earlier - exception this time I've wrapped the entire thing in a function called 'generateHeader'.

Code: Select all

    private function generateHeader($url) {
        $date = $this->getTimestamp();

        $password = md5($this->backoffice_password, true);

        $token_bytes = $this->gateway . $url . $date . $password;
        $token_hash = hash("sha256", $token_bytes, true);
        $token_base64 = base64_encode($token_hash);

        $auth_header = 'Basic '
                . 'usergroup="' . $this->backoffice_usergroup . '", '
                . 'username="' . $this->backoffice_username . '", '
                . 'timestamp="' . $date . '", '
                . 'token="' . $token_base64 . '"';

        return $auth_header;
Finally, using GuzzleHttp we can submit the request:

Code: Select all

 public function sendAuthorizationRequest() {
        $auth_header = $this->generateHeader('merchant/authenticate');

        $httpRequest = new Request('GET', 'merchant/authenticate', [
            'Authorization' => $auth_header

        $httpResponse = $this->client->send($httpRequest);

        if ($httpResponse->getStatusCode() != 200) {
            throw new Exception(
            "Received unexpected HTTP code from Iveri gateway. Received HTTP '{$httpResponse->getStatusCode()}'");

        return $httpResponse->getBody();
And we'll receive the timestamp of the server. Success.

Of course I've skipped a few pre-configuration steps to take into consideration such as the certificate verification and what not, but that's all described within the documentation and depends on what HTTP client you're using. With Guzzle, you really just need to specify the verification location so that the HTTP client can match against the servers certificate.
Posts: 2
Joined: Mon Apr 25, 2016 3:48 pm

Thu Jun 02, 2016 3:27 pm

Hi Stephen,

thanks for sharing your experiences! In my script was a bug. I used the incorrect time zone in my token generation method.

I changed it from

timestamp = DateTime.now.strftime("%Y%m%d%H%M%S%3N")


timestamp = DateTime.now.getutc.strftime("%Y%m%d%H%M%S%3N")

and it worked like a charm. I was so happy when I finally received the timestamp from the iVeri server.

Your code helped me a lot to build the token string for authentication. Thanks a lot for that.

Samora told us similar things by the way.

I have however concerns to use gateway.iveri.co.za for payment transactions because its SSL certificate is insecure. (https://www.ssllabs.com/ssltest/analyze ... veri.co.za)

Verifying agains the certificate "Builtin Object Token-Entrust Root Certification Authority - G2" from nedsecure worked in the end for portal.nedsecure.co.za. (Funny is that I coulnd not get Verification to work with gateway.iveri.co.za.)

My current status is:
https://portal.nedsecure.co.za/api/merc ... thenticate and the other "GET" Endpoints work. The "POST" endpoint 'api/transactions' however always returns error code 500 with no details for what I am doing wrong.

I find the WebAPI Developers Guide quite misleading because of the wrong links and the lack of endpoint descriptions.

Also I got XML responses where I expected JSON (e.g. GET /api/merchant/bins EP). Did I do sth. wrong?

Sorry for my incoherent sentences,

Post Reply