Skip to content

Signature generation for request and response

Signature algorithm

Parameter signature in create order request and response and in callbacks is generated with sha1 function. sha1 is applied to the string, which contains merchant payment secret key and all request or response parameters, concatenated in alphabetic order and separated by | symbol.

Example

Merchant request:

curl -i -X POST \
-H "Content-Type:application/json" \
-d \
'{
"request": {
"server_callback_url": "http://myshop/callback/",
"order_id": "TestOrder2",
"currency": "GEL",
"merchant_id": 1549901,
"order_desc": "Test payment",
"amount": 1000,
"signature": "91ea7da493a8367410fe3d7f877fb5e0ed666490"
}
}' \
'https://pay.flitt.com/api/checkout/url'

String used for signature build:

test|1000|GEL|1549901|Test payment|TestOrder2|http://myshop/callback/

Where test is payment secret key from test data

If parameter is absent or is empty then there is no need to add | symbol.

Signature validation example for response_url and server_callback_url POST response:

namespace Ipsp;
/**
 * Class Signature
   * @package Ipsp
   */
class Signature {
      /**
       * @var
       */
      private static $password;
      /**
       * @var
       */
      private static $merchant;
      /**
       * Set merchant password
       * @param String $password
       * @return mixed
       */
      public static function password($password){
          self::$password = $password;
      }
      /**
       * Set merchant id
       * @param String $merchant
       * @return mixed
       */
      public static function merchant( $merchant ){
          self::$merchant = $merchant;
      }
      /**
       * Generate request params signature
       * @param array $params
       * @return string
       */
      public static function generate(Array $params){
          $params['merchant_id'] = self::$merchant;
          $params = array_filter($params,'strlen');
          ksort($params);
          $params = array_values($params);
          array_unshift( $params , self::$password );
          $params = join('|',$params);
          return(sha1($params));
      }
      /**
       * Sign params with signature
       * @param array $params
       * @return array
       */
      public static function sign(Array $params){
          if(array_key_exists('signature',$params)) return $params;
          $params['signature'] = self::generate($params);
          return $params;
      }
      /**
       * Clean array params
       * @param array $data
       * @return array
       */
      public static function clean(Array $data){
          if( array_key_exists('response_signature_string',$data) )
              unset( $data['response_signature_string'] );
          unset( $data['signature'] );
          return $data;
      }
      /**
       * Check response params signature
       * @param array $response
       * @return bool
       */
      public static function check(Array $response){
          if(!array_key_exists('signature',$response)) return FALSE;
          $signature = $response['signature'];
          $response  = self::clean($response);
          return $signature == self::generate($response);
      }
}
from hashlib import sha1

def get_signature(secret_key, params):
    """
    :param secret_key: merchant secret
    :param params: POST parameters
    :return: signature string
    """
    data = [secret_key]
    data.extend([str(params[key]) for key in sorted(iter(params.keys()))
                 if params[key] != '' and not params[key] is None
                 and key != 'signature'])
    return sha1('|'.join(data).encode('utf-8')).hexdigest()

Solving problems with signature generation and validation

There are two typical cases when the signature parameter verification error occurs.

Case 1: in response to Flitt API call

When request for the create order, reverse, get status or any other request with the parameter signature is sent from merchant to the Flitt API, and the response is returned:

    {
        "response": {
            "error_code": 1014,
            "error_message": "Invalid signature",
            "request_id": "3mwpcKoenYZ0w",
            "response_status": "failure"
        }
    }

If the request is sent to the Flitt API, and the response is returned as "error_message": "Invalid signature", perform the following checks:

  • check that you used the correct payment secret key from the Technical Settings menu in the Merchant Portal:

  • if the request contains non-Latin encoding, then it is sent in encoding UTF-8

  • make sure that a parameter with a value of 0 is not null by your programming language

  • log the line in the program code to which you apply SHA1 during the generation of the signature parameter. Compare it with the string that returned in the error text (marked in red): “Invalid signature signature: ``6bd069be8a6e2f2bbe176df00ba63cc681ca38aa``; response_signature_string: ``**********|125|GEL|1549901|demo order 789|Demo123456``“. Note that in the text of the error the merchant’s payment key will be masked with * symbol

  • check if you send empty parameters in the API request. If yes, then in the line that participates in the signature, the | separator symbol for each such empty parameter does not need to be included

  • if you are developing with the PHP programming language, use the example function php-inline public static function generate(Array $params):

  • make sure that the result of the SHA1 function is lowercase. Correct: 6bd069be8a6e2f2bbe176df00ba63cc681ca38aa. Incorrect: 6BD069BE8A6E2F2BBE176DF00BA63CC681CA38AA

  • make sure that the signature parameter is not included in your signature calculation

  • make sure that if you use the API endpoint /api/recurring, then you only include the necessary parameters in the signature, but not those from the /api/redirect endpoint

Case 2: in callback to server_callback_url or redirect to response_url

When the Flitt server returned a POST response or callback to server_callback_url or response_url and you try to generate own signature and compare it with the signature parameter from the POST response, the signatures do not match

If the Flitt API returned a POST response to the pages specified in the server_callback_url or response_url parameters, but when you try to generate a signature and compare it with the signature parameter in the POST response, the signature does not match

{
    "response": {
        "rrn": "",
        "masked_card": "",
        "sender_cell_phone": "",
        "sender_account": "",
        "currency": "GEL",
        "fee": "",
        "reversal_amount": "0",
        "settlement_amount": "0",
        "actual_amount": "",
        "response_description": "",
        "sender_email": "",
        "order_status": "expired",
        "response_status": "success",
        "order_time": "28.02.2018 19:18:16",
        "actual_currency": "",
        "order_id": "TestOrder2",
        "tran_type": "purchase",
        "eci": "",
        "settlement_date": "",
        "payment_system": "",
        "approval_code": "",
        "merchant_id": 1549901,
        "settlement_currency": "",
        "payment_id": 83456044,
        "card_bin": "",
        "response_code": "",
        "card_type": "",
        "amount": "1000",
        "signature": "268b8f189f97c85696134fe6ae0f7f5ab93f28d5",
        "product_id": "",
        "merchant_data": "",
        "rectoken": "",
        "rectoken_lifetime": "",
        "verification_status": "",
        "parent_order_id": "",
        "fee_oplata": "0",
        "additional_info": "{\"capture_status\": null, \"capture_amount\": null, \"reservation_data\": null, \"transaction_id\": null, \"bank_response_code\": null, \"bank_response_description\": null, \"client_fee\": null, \"settlement_fee\": 0.0, \"bank_name\": null, \"bank_country\": null, \"card_type\": null, \"card_product\": null, \"card_category\": null, \"timeend\": \"01.03.2018 05:18:17\", \"ipaddress_v4\": \"52.30.149.20\", \"payment_method\": null}",
        "response_signature_string": "**********|{\"capture_status\": null, \"capture_amount\": null, \"reservation_data\": null, \"transaction_id\": null, \"bank_response_code\": null, \"bank_response_description\": null, \"client_fee\": null, \"settlement_fee\": 0.0, \"bank_name\": null, \"bank_country\": null, \"card_type\": null, \"card_product\": null, \"card_category\": null, \"timeend\": \"01.03.2018 05:18:17\", \"ipaddress_v4\": \"52.30.149.20\", \"payment_method\": null}|1000|GEL|0|1549901|TestOrder2|expired|28.02.2018 19:18:16|83456044|success|0|0|purchase"
    }
}

To diagnose the cause of a signature mismatch, follow these steps:

  • make sure that the parameter with a value of 0 is not brought to empty or null in your programming language
  • make sure that the response_signature_string and signature parameters are not included in the signature calculation (the response_signature_string parameter is returned only if the merchant is in test mode and contains hint how the signature was formed in response)
  • if the request contains non-Latin letters, then it is sent in UTF-8
  • in the program code, pledge a line to which you apply SHA1 during the formation of the signature parameter. Compare it with the string that returned in the response_signature_string parameter
  • check if empty parameters are returned in the response. If yes, then in the string which participates in the signature, it is not necessary to include the symbol separator | for each empty parameter
  • make sure that the result of the SHA1 function is lowercase. Correct: 6bd069be8a6e2f2bbe176df00ba63cc681ca38aa. Incorrect: 6BD069BE8A6E2F2BBE176DF00BA63CC681CA38AA