APPROVE API


APPROVE API

The APPROVE API provides full programatic access to the APPROVE functions. It allows your business to integrate your systems and sites with APPROVE seamlessly.

APPROVE API Screenshot

Visit the full APPROVE API documentation.

Retrieving Your API Key

To retrieve your API Key, log-in to APPROVE and go to APPROVE Settings > Account > API Key.

{primary} All APPROVE solutions required an APPROVE subscription.


Common Use Cases for APPROVE API


API Webhooks

To see available webhooks go to APPROVE Settings > API Webhooks.

IF the webhook selected contains PII (Personally Identifiable Information) these fields data will be encrypted as to prevent data exposure.

If there is encrypted data, The JSON sent will include a field encrypted_fields

If this is set and not empty it will be a comma seperated list of fields that will need decrypted in the body of the api data portion of the message.


API Signature Verification

First retrieve an array of all headers sent to your server except for the header X-message-signature which must be left out.

Convert this to a json encoded string.

Concat the json encoded headers with the json encoded body sent with the message and create a HMAC hash with this data and your encryption_secret that can be obtained from your APPROVE settings pages.

We base64url encode the signature so you will need to do the same to compare.

IF using php this can be done as follows:

    function base64url_encode($data) {

        // decode standard base64 encoded string
        $data = base64_encode($data);

        // replace '+/' chars with '-_' in the encoded string and remove all '='
        $data = str_replace(['+','/','='], ['-','_',''], $data);

        return $data;
    }

IF using javascript it can be done as follows:


    function base64url_encode(data) {
        // convert original to base64 encoding using btoa() Binary to ASCII
        data = btoa(data);

        // replace '+-' chars with '-_' in the encoded string and remove all '='
        data = data
            .replace(/+/g, '-')
            .replace(/\//g, '_')
            .replace(/\=/g, '');

        return data; 
    }

To create a hash to verify against the signature use a process similar to the following:

{warning} IF using any client side technology it is best to NEVER allow the client to recieve your encryption_secret, api key, or approve-id

    function create_message_hash($message_body_string, $message_header_string, $encryption_secret) {

        $hash_algo = "sha256";

        // hash the combined post_data and headers as raw binary hash_hmac with hash algorithm default = 'sha256'
        $hash = hash_hmac($hash_algo, $message_body_string.$message_header_string, $encryption_secret, $raw_binary=true);

        // base64url encode the hash and return as signature
        $signature = base64url_encode($hash);
        return $signature;
    }

EXAMPLE function written in javascript:

This example uses the crypto-js lirary which can be found here https://github.com/brix/crypto-js

    function create_message_hash(message_body_string, message_header_string, encryption_secret) {

        // we utilize the HMAC sha256 algorithm
        var hash = CryptoJS.HmacSHA256(message_body_string + message_header_string, encryption_secret);

        hash = base64url_encode(hash);

        return hash;
    }


API Data Decryption

All encrypted data will be encoded using the base64 url safe encoding.

To decode url safe base64 encoding you need to either use a language available base64url function or create your own.

The encoded string will need to have the characters - AND _ replaced with + AND / respectively. If your language requires the base64 encoded string be returned with proper padding you will have to add the character = to the end of the string padding as many times as necessary.

IF using php this can be done as follows:

    function base64url_decode($data) {
        // replace '-_' chars with '+/' in the encoded string
        $data = str_replace(['-','_'], ['+','/'], $data);

        // pad the string with '=' at the end so it matches correct initial encoded byte size
        $data = str_pad($data, (strlen($data) % 4), '=', STR_PAD_RIGHT);

        // decode standard base64 encoded string
        $data = base64_decode($data);

        return $data;
    }

IF using javascript it can be done as follows:

    function base64url_decode(data) {
        // replace '-_' chars with '+/' in the encoded string
        data = data
            .replace(/-/g, '+')
            .replace(/_/g, '/');

        // pad the string with '=' at the end so it matches correct initial encoded byte size
        var diff = data.length % 4;
        var pad_length = 4 - diff;
        if(pad_length) {
            while (pad_length--) {
                data += '=';
            }
        }

        // convert base64 to original encoding using atob() ASCII to Binary
        data = atob(data);
        return data; 
    }



DECODING data

TO Decode and decrypt any data you will need to use a process similar to the process that follows:

PHP Example decryption function

    function decode_data($data, $encryption_secret) {
        // Set cipher. Default = 'AES-256-CBC' you will be informed if different
        $cipher = "AES-256-CBC"; 

        // Set hash_algorithm. Default = sha256 you will be informed if different
        $hash_algo = "sha256";

        // Set hash length. Default = 32 for the default 'sha256' binary hash you will be informed if different
        $hash_length = 32;

        // Decode the encrypted string from base64url encoding
        $data = base64url_decode($data);

        // calculate iv length based off from the cipher used default = AES-256-CBC
        $iv_length = openssl_cipher_iv_length($cipher); // (should always be 16 when AES-256-CBC is used)

        // get calculated iv for use in decryption
        $iv = substr($data, 0, $iv_length);

        // get calculated hash for use in hash comparison using the initial hash_length 
        // default hash is a raw binary hash_hmac using hash algorithm of 'sha256' which has a char length of '32'
        $hash = substr($data, $iv_length, $hash_length);

        // get original encrypted data 
        $data_raw = substr($data, $iv_length + $hash_length);

        // decrypt original encrypted data
        $openssl_options = OPENSSL_RAW_DATA;
        $decrypted_data = openssl_decrypt($data_raw, $cipher, $secret, $openssl_options, $iv);

        // recalculate hash and compare to the original to verify encryption
        $returned_data = false;
        $calculated_hash = hash_hmac('sha256', $data_raw, $secret, $raw_binary=true);
        // compare original calculated hash with newly calculated hash 
        // this is a PHP 5.6+ timing attack safe comparison
        if (hash_equals($hash, $calculated_hash)) {
            // if the comparison passes then this data has not been modified and the decrypted data can be trusted
            $returned_data = $decrypted_data;
        }

        return $returned_data;

    }

EXAMPLE function written in javascript:

This example uses the crypto-js lirary which can be found here https://github.com/brix/crypto-js


    function decrypt_data(data, encryption_secret) {

        encryption_secret = crypto.enc.Utf8.parse(encryption_secret);

        var decrypted_message = "";

        // Set cipher. Default = 'AES-256-CBC' you will be informed if different
        var cipher = "AES-CBC"; 

        // Set hash_algorithm. Default = sha256 you will be informed if different
        var hash_algo = "sha256";

        // Set hash length. Default = 32 for the default 'sha256' binary hash you will be informed if different
        var hash_length = 32;

        var data = base64url_decode(data);

        // calculate iv length based off from the cipher used default = AES-256-CBC
        var iv_length = 16; // length is 16 when iv is created with AES-256-CBC

        // get calculated iv for use in decryption
        var iv = crypto.enc.Hex.parse(data.substring(0, iv_length)); 

        // get calculated hash for use in hash comparison using the initial hash_length 
        // default hash is a raw binary hash_hmac using hash algorithm of 'sha256' which has a char length of '32'
        // if you want to rehash and verify retrieve the original hash
        var hash = data.substring(iv.length, hash_length);

        // get original encrypted data 
        var data_raw = data.substring(iv.length + hash_length);

        decrypted_data = crypto.AES.decrypt(
            data_raw, 
            encryption_secret, {
                iv,
                mode: crypto.mode.CBC,
                format: crypto.format.Hex
            })
            .toString(crypto.enc.Utf8);

        return decrypted_data;

}

We use the openssl libraries which are available in many languages. You can use these libraries to create a similar or same process in your language of choice. We will add more examples as they are created.