Signature generation and verification

Overview

The data communication between the merchant's web service and the ecommpay payment platform is protected by using the TLS (Transport Layer Security) protocol version 1.2 or later. This ensures the confidentiality of the data being transmitted, though the protocol cannot guarantee the message integrity and ensure that the message author possesses the secret key. Therefore, every message must be digitally signed by using the secret key issued by ecommpay for the merchant and known only to the merchant and the ecommpay payment platform.

Regardless of the interface that is used for working with the payment platform, digital signatures should be included in all requests, callbacks (for the requests processed within the asynchronous interaction model), and certain responses (for the requests processed within the synchronous interaction model). Thus, before sending any request to the platform, a signature should be generated and included in the request to be sent; and in case of receiving responses and callbacks from the platform, it is necessary to verify the received data by comparing the signatures to the ones generated on the merchant side. To implement the digital signature generation and verification, you can use either your own solutions or the SDK available from ecommpay (details).

This section describes the algorithms for the digital signature generation and the data integrity verification, including examples with the use of these algorithms and interactive forms for testing the workflows using signatures.

Signature generation

Signing algorithm

The algorithm input includes the following:

  1. Data to sign.

    Generally, this is the request body, all request parameters without the signature, or the configObj JavaScript object with parameters that do not include the signature parameter.

  2. A signing key.
    Note: For working with the Data API, it is necessary to use keys generated via the Dashboard interface together with tokens (for more information, see the Data access model section.)

    For the purposes of debugging and testing your signing algorithm implementation, you are free to use any signing key. For signing requests in production environment, you are required to use your production secret key.

Depending on the algorithm implementation, its output may be either a signature or signed data. Generally, the algorithm output consists of an object or a request body in JSON format with the signature parameter.

The algorithm description, the examples, and test forms below include the most common algorithm implementation relevant for use when working with the Payment Page API, Gate API, and Data API.

Thus, the algorithm includes the following steps:

  1. Input validation. Make sure the following requirements are met:

    1. The structure of data to be signed must correspond to the JSON format. In case of using Payment Page, JavaScript objects can be used.
    2. Data to sign does not contain any signature parameter even if it is empty.
    3. The signing key is readily available.
  2. Conversion of all the strings to UTF-8 with parameters sorted in natural order. Complete the following steps:

    1. Encode any Boolean values as follows: replace false with 0, replace true with 1. Mind that this rule applies only to Boolean values. If any string parameter contains "false" or "true" string value, the value is not replaced with 0 or 1 but is treated as any other string value (for example the recurring: "{type: \"U\",register: true}" parameter doesn’t require replacing true with 1).
    2. Convert each parameter into a string that contains the full path to the parameter (with all its parents), parameter name, and parameter value:

      <parent_1>:...:<parent_n>:<parameter_name>:<parameter_value>

      where parents are the object(s) and/or arrays in which the parameter is contained. Parents are ordered by embedding level starting with the topmost one. The parent names, parameter name, and parameter value are delimited by colon (:); delete any commas between “key-value” pairs and any quotation marks that delimit string values.

    3. Leave any empty parameter values empty. In other words, do not replace any empty values with blank space or null. For instance, "payment_description":"" is replaced with payment_description:.
    4. Add index numbers to array elements starting with zero, for instance ["alpha", "beta", "gamma"] is replaced with three strings: 0:alpha, 1:beta, and 2:gamma.
    5. Empty arrays are totally ignored and not included in the string set used to generate the signature.
    6. Convert all the strings to UTF-8.
    7. Sort the strings in natural sort order and join them in a single string by using semicolon (;) as a delimiter.
  3. Calculation of HMAC code by using the key and the SHA-512 hash function. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key. The HMAC code must be calculated as a raw binary data.
  4. Encoding the HMAC code by using the Base64 scheme. Encoding the HMAC code by using the Base64 scheme to obtain the signature for the initial data.
  5. Adding signature. Add the signature parameter to the request body using the signature from the previous step as its value.

Example of purchase request through Payment Page

Suppose that you need to generate a signature for a Payment Page request in the following scenario:

  • Secret key obtained from the ecommpay support service: secret.
  • The configObj object that does not yet contain the signature parameter is the following:
    {
    "project_id": 12345, 
    "payment_id": "X03936", 
    "payment_amount": 2035, 
    "payment_currency": "USD",
    "payment_description": "Guyliner purchase",
    "customer_first_name": "Jack",
    "customer_id": "user007",
    "customer_last_name": "Sparrow",
    "customer_phone": "02081234567",
    "close_on_missclick": true,
    "signature": "<signature that needs to be generated>" 
    }

The task is to generate the signature; in other words, you need to compute the value for the signature parameter. The signature is generated as follows:

  1. Make sure there is no signature parameter in your request even it is empty:
    {
    "project_id": 12345, 
    "payment_id": "X03936", 
    "payment_amount": 2035, 
    "payment_currency": "USD",
    "payment_description": "Guyliner purchase",
    "customer_first_name": "Jack",
    "customer_id": "user007",
    "customer_last_name": "Sparrow",
    "customer_phone": "02081234567",
    "close_on_missclick": true,
    "signature": "<signature that needs to be generated>" 
    }
  2. Convert all strings to UTF-8 as per algorithm description:
    project_id:12345 
    payment_id:X03936
    payment_amount:2035
    payment_currency:USD
    payment_description:Guyliner purchase
    customer_first_name:Jack
    customer_id:user007
    customer_last_name:Sparrow
    customer_phone:02081234567
    close_on_missclick:1
  3. Sort the strings in natural sort order:
    close_on_missclick:1
    customer_first_name:Jack
    customer_id:user007
    customer_last_name:Sparrow
    customer_phone:02081234567
    payment_amount:2035
    payment_currency:USD
    payment_description:Guyliner purchase
    payment_id:X03936
    project_id:12345
    
  4. Join all the strings in a single string by using semicolon (;) as a delimiter:
    close_on_missclick:1;customer_first_name:Jack;customer_id:user007;customer_last_name:Sparrow;customer_phone:02081234567;payment_amount:2035;payment_currency:USD;payment_description:Guyliner purchase;payment_id:X03936;project_id:12345
  5. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key, and then encode the HMAC code by using the Base64 scheme:
    SyA3cx/dmFrwjRcpbnwEK9zaklWKR9buIfTctQob/EHUTutFLpI0zWpSDFEWEwbZt/04i83395RCdEhtUMw83A==
  6. Add the resulting signature in the configObj object:
    {
    "project_id": 12345, 
    "payment_id": "X03936", 
    "payment_amount": 2035, 
    "payment_currency": "USD",
    "payment_description": "Guyliner purchase",
    "customer_first_name": "Jack",
    "customer_id": "user007",
    "customer_last_name": "Sparrow",
    "customer_phone": "02081234567",
    "close_on_missclick": true,
    "signature": "SyA3cx/dmFrwjRcpbnwEK9zaklWKR9buIfTctQob/EHUTutFLpI0zWpSDFEWEwbZt/04i83395RCdEhtUMw83A==" 
    }

Below you can find an interactive form that allows you to test signature generation when sending requests for opening Payment Page.

Note: To ensure correct processing of parameters specified in real requests for opening Payment Page, familiarise yourself with the requirements for encoding nested objects listed in Parameters for opening payment form and the articles describing the capabilities of the payment form. When you specify nested objects that do not conform to these requirements, the signature in the interactive testing form will still be generated according to the algorithm, but this signature cannot be used for real requests because it is generated with the use of incorrect input data.

Example of purchase request through Gate

Suppose that you need to generate the signature for a Gate request in the following scenario:

  • Signing key : secret.
  • Preliminary request body version where the value for the signature is missing:
    {
        "general": {
            "project_id": 3254,
            "payment_id": "id_38202316",
           "signature": "<signature that needs to be generated>" 
        },
        "customer": {
            "id": "585741",
            "email": "johndoe@mycompany.com",
            "first_name": "John",
            "last_name": "Doe",
            "address": "Downing str., 23",
            "identify": {
                "doc_number": "54122312544"
            },
            "ip_address": "111.222.333.444"
        },
        "payment": {
            "amount": 10800,
            "currency": "USD",
            "description": "Computer keyboards"
        },
        "receipt_data": {
            "positions": [
                {
                    "quantity": "10",
                    "amount": "108",
                    "description": "Computer keyboard"
                }
            ]
        },
        "return_url": {
            "success": "https://paymentpage.mycompany.com/complete-redirect?id=success",
            "decline": "https://paymentpage.mycompany.com/complete-redirect?id=decline"
        }
    }

The task is to generate the signature; in other words, you need to compute the value for the signature parameter and add it in the request. Complete the following steps:

  1. Make sure there is no signature parameter in your request even if it is empty:
    {
        "general": {
            "project_id": 3254,
            "payment_id": "id_38202316",
    "signature": "<signature that needs to be generated>"
        },
        "customer": {
            "id": "585741",
            "email": "johndoe@mycompany.com",
            "first_name": "John",
            "last_name": "Doe",
            "address": "Downing str., 23",
            "identify": {
                "doc_number": "54122312544"
            },
            "ip_address": "111.222.333.444"
        },
        "payment": {
            "amount": 10800,
            "currency": "USD",
            "description": "Computer  keyboards"
        },
        "receipt_data": {
            "positions": [
                {
                    "quantity": "10",
                    "amount": "108",
                    "description": "Computer keyboard"
                }
            ]
        },
        "return_url": {
            "success": "https://paymentpage.mycompany.com/complete-redirect?id=success",
            "decline": "https://paymentpage.mycompany.com/complete-redirect?id=decline"
        }
    }
  2. Convert all the strings to UTF-8 as per algorithm description:
    general:project_id:3254
    general:payment_id:id_38202316
    customer:id:585741
    customer:email:johndoe@mycompany.com
    customer:first_name:John
    customer:last_name:Doe
    customer:address:Downing str., 23
    customer:identify:doc_number:54122312544
    customer:ip_address:111.222.333.444
    payment:amount:10800
    payment:currency:USD
    payment:description:Computer keyboards
    receipt_data:positions:0:quantity:10
    receipt_data:positions:0:amount:108
    receipt_data:positions:0:description:Computer keyboard
    return_url:success:https://paymentpage.mycompany.com/complete-redirect?id=success
    return_url:decline:https://paymentpage.mycompany.com/complete-redirect?id=decline
  3. Sort the strings in natural sort order:
    customer:address:Downing str., 23
    customer:email:johndoe@mycompany.com
    customer:first_name:John
    customer:id:585741
    customer:identify:doc_number:54122312544
    customer:ip_address:111.222.333.444
    customer:last_name:Doe
    general:payment_id:id_38202316
    general:project_id:3254
    payment:amount:10800
    payment:currency:USD
    payment:description:Computer keyboards
    receipt_data:positions:0:amount:108
    receipt_data:positions:0:description:Computer keyboard
    receipt_data:positions:0:quantity:10
    return_url:decline:https://paymentpage.mycompany.com/complete-redirect?id=decline
    return_url:success:https://paymentpage.mycompany.com/complete-redirect?id=success
    
  4. Join all the strings in a single string by using semicolon (;) as a delimiter:
    customer:address:Downing str., 23;customer:email:johndoe@mycompany.com;customer:first_name:John;customer:id:585741;customer:identify:doc_number:54122312544;customer:ip_address:111.222.333.444;customer:last_name:Doe;general:payment_id:id_38202316;general:project_id:3254;payment:amount:10800;payment:currency:USD;payment:description:Computer keyboards;receipt_data:positions:0:amount:108;receipt_data:positions:0:description:Computer keyboard;receipt_data:positions:0:quantity:10;return_url:decline:https://paymentpage.mycompany.com/complete-redirect?id=decline;return_url:success:https://paymentpage.mycompany.com/complete-redirect?id=success
  5. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key, and then encode the HMAC code by using the Base64 scheme:
    VLLZzVNGevQNhr1b4TEhbC4qqHD17Kyn/M6FPNN93ttyk/amJgD/R6dayTKVvW6/QCRdq4hOf8R2w/xbUa8f2w==
  6. Add the resulting signature in the request body:
    {
        "general": {
            "project_id": 3254,
            "payment_id": "id_38202316",
           "signature": "VLLZzVNGevQNhr1b4TEhbC4qqHD17Kyn/M6FPNN93ttyk/amJgD/R6dayTKVvW6/QCRdq4hOf8R2w/xbUa8f2w=="
        },
        "customer": {
            "id": "585741",
            "email": "johndoe@mycompany.com",
            "first_name": "John",
            "last_name": "Doe",
            "address": "Downing str., 23",
            "identify": {
                "doc_number": "54122312544"
            },
            "ip_address": "111.222.333.444"
        },
        "payment": {
            "amount": 10800,
            "currency": "USD",
            "description": "Computer keyboards"
        },
        "receipt_data": {
            "positions": [
                {
                    "quantity": "10",
                    "amount": "108",
                    "description": "Computer keyboard"
                }
            ]
        },
        "return_url": {
            "success": "https://paymentpage.mycompany.com/complete-redirect?id=success",
            "decline": "https://paymentpage.mycompany.com/complete-redirect?id=decline"
        }
    }

Below you can find an interactive form that allows you to test signature generation when sending the Gate API requests.

Example of data request through Data API

Suppose that you need to generate a signature for a Dashboard request in the following scenario:

  • Signing key : secret.
  • Preliminary request body version where the value for the signature is missing:
    {
      "token": "WKiarERJ5pcceNerpM9R5TNnyPTQMl",
      "interval": {
        "from": "2020-01-01 14:53:55",
        "to": "2020-01-30 13:53:59"
      },
      "project_id": [
        183
      ],
      "limit": 3,
      "offset": 0,
      "tz": "Asia/Singapore",
     "signature": "<signature that needs to be generated>"
    }

The task is to generate the signature; in other words, you need to compute the value for the signature parameter and add it in the request. Complete the following steps:

  1. Make sure there is no signature parameter in your request even it is empty:
    {
      "token": "WKiarERJ5pcceNerpM9R5TNnyPTQMl",
      "interval": {
        "from": "2020-01-01 14:53:55",
        "to": "2020-01-30 13:53:59"
      },
      "project_id": [
        183
      ],
      "limit": 3,
      "offset": 0,
      "tz": "Asia/Singapore",
     "signature": "<signature that needs to be generated>"
    }
  2. Convert all the strings to UTF-8 as per algorithm description:
    token:WKiarERJ5pcceNerpM9R5TNnyPTQMl
    interval:from:2020-01-01 14:53:55
    interval:to:2020-01-30 13:53:59
    project_id:0:183
    limit:3
    offset:0
    tz:Asia/Singapore
  3. Sort the strings in natural sort order:
    interval:from:2020-01-01 14:53:55
    interval:to:2020-01-30 13:53:59
    limit:3
    offset:0
    project_id:0:183
    token:WKiarERJ5pcceNerpM9R5TNnyPTQMl
    tz:Asia/Singapore
    
  4. Join all the strings in a single string by using semicolon (;) as a delimiter:
    interval:from:2020-01-01 14:53:55;interval:to:2020-01-30 13:53:59;limit:3;offset:0;project_id:0:183;token:WKiarERJ5pcceNerpM9R5TNnyPTQMl;tz:Asia/Singapore
  5. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key, and then encode the HMAC code by using the Base64 scheme:
    Ini3aKje6aZskajTuRS761YOzVqierlVRafZdxIz48wmVnL7yxgy9vDsp7T2/LGPGHJ/DHoKOgP7VqObJALrUA==
  6. Add the resulting signature in the request body:
    {
      "token": "WKiarERJ5pcceNerpM9R5TNnyPTQMl",
      "interval": {
        "from": "2020-01-01 14:53:55",
        "to": "2020-01-30 13:53:59"
      },
      "project_id": [
        183
      ],
      "limit": 3,
      "offset": 0,
      "tz": "Asia/Singapore",
     "signature": "Ini3aKje6aZskajTuRS761YOzVqierlVRafZdxIz48wmVnL7yxgy9vDsp7T2/LGPGHJ/DHoKOgP7VqObJALrUA=="
    }

Below you can find an interactive form that allows you to test signature generation when sending the Data API requests.

Figure 1. Request signature generation form

Signature verification

Verification algorithm

The algorithm input includes the following:

  1. Signed data to verify.

    Generally, this is callback or response body in JSON format with the signature parameter.

  2. Verification key. It must be the same key that was previously used for signing the data to verify.

Depending on the algorithm implementation, its output may be either a generated signature or the information whether the generated signature matches the one included in the response or callback.

The algorithm description, the examples, and test forms below use the most common algorithm implementation that includes callback or response body in JSON format as input (without the signature parameter) and output (with the signature parameter) which is the result of signature verification.

Thus, the algorithm includes the following steps:

  1. Input validation Make sure the following requirements are met:

    1. Data conforms to the JSON format.
    2. Data to sign contains a signature parameter with the signature value.
    3. The signing key is readily available.
  2. Extracting signature from the data to verify. Store the value of the signature parameter value for further reference and remove the parameter from the input data.
  3. Generate signature for the data to verify. Complete steps 2 through 4 as specified in the signature generation algorithm description. (For more details, see the following link):
    1. Conversion of all the strings to UTF-8 with parameters sorted in natural order.
    2. Calculation of HMAC code by using the key and the SHA-512 hash function.
    3. Encoding the HMAC code by using the Base64 scheme.
  4. Signature matching Compare the generated signature with the signature stored in step 2. If the signatures match, the data are authentic and its integrity is considered confirmed; otherwise, the data is considered compromised and cannot be used for production purposes.

Example of callback verification

Suppose that you need to verify the signature of a callback in the following scenario:

  • Signing key : secret.
  • The callback body contains the following information:
    Figure 2. Callback body
    {
        "customer": {
            "id": "782572"
        },
        "account": {
            "number": "424242******4242",
            "token": "c8175453f68ec7c8fb3f052b8d786c661261efebcb91155327a6c7b8f8e66359",
            "type": "visa",
            "card_holder": "TEST TEST",
            "expiry_month": "01",
            "expiry_year": "2025"
        },
        "project_id": 28051,
        "payment": {
            "id": "5242723",
            "type": "purchase",
            "status": "success",
            "date": "2023-03-10T12:26:17+0000",
            "method": "card",
            "sum": {
                "amount": 5200,
                "currency": "EUR"
            },
            "description": ""
        },
        "operation": {
            "sum_initial": {
                "amount": 5200,
                "currency": "EUR"
            },
            "sum_converted": {
                "amount": 5200,
                "currency": "EUR"
            },
            "code": "0",
            "message": "Success",
            "provider": {
                "id": 6,
                "payment_id": "16784511766816",
                "auth_code": "563253",
                "endpoint_id": 6,
                "date": "2023-03-10T10:26:17+0000"
            },
            "id": 5028800010128225,
            "type": "sale",
            "status": "success",
            "date": "2023-03-10T12:26:17+0000",
            "created_date": "2023-03-10T12:26:15+0000",
            "request_id": "1f6d3ac37444142f5bd27e7491faa360633fd5a2-fc98e73d475fa4cd6ee02fc6340c964f0267b3d8-05028801"
        },
        "signature": "IszjSnH+UqFp88DF0giI/jUTDHOnfPxc83j2VD/jN4loB9wbHwiO5+KvHfdFE4nBPHhhxD6TXbOkGnRINFTTmg=="
    }

The signature is verified as follows:

  1. Remove the signature parameter and its value from the callback:
    {
        "customer": {
            "id": "782572"
        },
        "account": {
            "number": "424242******4242",
            "token": "c8175453f68ec7c8fb3f052b8d786c661261efebcb91155327a6c7b8f8e66359",
            "type": "visa",
            "card_holder": "TEST TEST",
            "expiry_month": "01",
            "expiry_year": "2025"
        },
        "project_id": 28051,
        "payment": {
            "id": "5242723",
            "type": "purchase",
            "status": "success",
            "date": "2023-03-10T12:26:17+0000",
            "method": "card",
            "sum": {
                "amount": 5200,
                "currency": "EUR"
            },
            "description": ""
        },
        "operation": {
            "sum_initial": {
                "amount": 5200,
                "currency": "EUR"
            },
            "sum_converted": {
                "amount": 5200,
                "currency": "EUR"
            },
            "code": "0",
            "message": "Success",
            "provider": {
                "id": 6,
                "payment_id": "16784511766816",
                "auth_code": "563253",
                "endpoint_id": 6,
                "date": "2023-03-10T10:26:17+0000"
            },
            "id": 5028800010128225,
            "type": "sale",
            "status": "success",
            "date": "2023-03-10T12:26:17+0000",
            "created_date": "2023-03-10T12:26:15+0000",
            "request_id": "1f6d3ac37444142f5bd27e7491faa360633fd5a2-fc98e73d475fa4cd6ee02fc6340c964f0267b3d8-05028801"
        },
        "signature": "IszjSnH+UqFp88DF0giI/jUTDHOnfPxc83j2VD/jN4loB9wbHwiO5+KvHfdFE4nBPHhhxD6TXbOkGnRINFTTmg=="
    }
  2. Convert all parameter strings to UTF-8 according to the algorithm description:
    customer:id:782572
    account:number:424242******4242
    account:token:c8175453f68ec7c8fb3f052b8d786c661261efebcb91155327a6c7b8f8e66359
    account:type:visa
    account:card_holder:TEST TEST
    account:expiry_month:01
    account:expiry_year:2025
    project_id:28051
    payment:id:5242723
    payment:type:purchase
    payment:status:success
    payment:date:2023-03-10T12:26:17+0000
    payment:method:card
    payment:sum:amount:5200
    payment:sum:currency:EUR
    payment:description:
    operation:sum_initial:amount:5200
    operation:sum_initial:currency:EUR
    operation:sum_converted:amount:5200
    operation:sum_converted:currency:EUR
    operation:code:0
    operation:message:Success
    operation:provider:id:6
    operation:provider:payment_id:16784511766816
    operation:provider:auth_code:563253
    operation:provider:endpoint_id:6
    operation:provider:date:2023-03-10T10:26:17+0000
    operation:id:5028800010128225
    operation:type:sale
    operation:status:success
    operation:date:2023-03-10T12:26:17+0000
    operation:created_date:2023-03-10T12:26:15+0000
    operation:request_id:1f6d3ac37444142f5bd27e7491faa360633fd5a2-fc98e73d475fa4cd6ee02fc6340c964f0267b3d8-05028801
    
  3. Sort the strings in natural sort order:
    account:card_holder:TEST TEST
    account:expiry_month:01
    account:expiry_year:2025
    account:number:424242******4242
    account:token:c8175453f68ec7c8fb3f052b8d786c661261efebcb91155327a6c7b8f8e66359
    account:type:visa
    customer:id:782572
    operation:code:0
    operation:created_date:2023-03-10T12:26:15+0000
    operation:date:2023-03-10T12:26:17+0000
    operation:id:5028800010128225
    operation:message:Success
    operation:provider:auth_code:563253
    operation:provider:date:2023-03-10T10:26:17+0000
    operation:provider:endpoint_id:6
    operation:provider:id:6
    operation:provider:payment_id:16784511766816
    operation:request_id:1f6d3ac37444142f5bd27e7491faa360633fd5a2-fc98e73d475fa4cd6ee02fc6340c964f0267b3d8-05028801
    operation:status:success
    operation:sum_converted:amount:5200
    operation:sum_converted:currency:EUR
    operation:sum_initial:amount:5200
    operation:sum_initial:currency:EUR
    operation:type:sale
    payment:date:2023-03-10T12:26:17+0000
    payment:description:
    payment:id:5242723
    payment:method:card
    payment:status:success
    payment:sum:amount:5200
    payment:sum:currency:EUR
    payment:type:purchase
    project_id:28051
  4. Join all strings in a single string by using semicolon (;) as a delimiter:
    account:card_holder:TEST TEST;account:expiry_month:01;account:expiry_year:2025;account:number:424242******4242;account:token:c8175453f68ec7c8fb3f052b8d786c661261efebcb91155327a6c7b8f8e66359;account:type:visa;customer:id:782572;operation:code:0;operation:created_date:2023-03-10T12:26:15+0000;operation:date:2023-03-10T12:26:17+0000;operation:id:5028800010128225;operation:message:Success;operation:provider:auth_code:563253;operation:provider:date:2023-03-10T10:26:17+0000;operation:provider:endpoint_id:6;operation:provider:id:6;operation:provider:payment_id:16784511766816;operation:request_id:1f6d3ac37444142f5bd27e7491faa360633fd5a2-fc98e73d475fa4cd6ee02fc6340c964f0267b3d8-05028801;operation:status:success;operation:sum_converted:amount:5200;operation:sum_converted:currency:EUR;operation:sum_initial:amount:5200;operation:sum_initial:currency:EUR;operation:type:sale;payment:date:2023-03-10T12:26:17+0000;payment:description:;payment:id:5242723;payment:method:card;payment:status:success;payment:sum:amount:5200;payment:sum:currency:EUR;payment:type:purchase;project_id:28051
  5. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key, and then encode the HMAC code by using the Base64 scheme:
    Y0qjN9dDnPTdddkVvXKS1pGp2z8ZpIl60P1CocND3YRxuBNx05ZMnhUaGFt90fPzgwsI/UpLw0q2RR/XTiDQBg==
  6. Compare the generated signature and the one included in the callback.

    In our case, the signatures differ which means that the callback is invalid and must be ignored.

Below you can find an interactive form that allows you to test signature verification.

Example of verifying a response with operations data

Suppose that you need to verify the signature of a response in the following scenario:

  • Signing key : secret.
  • The response body contains the following information:
    Figure 3. Response body
    {
      "operations": [
        {
          "project_id": "183",
          "operation_id": "9048253065548",
          "payment_id": "EP834a-40521580376090593",
          "operation_type": "cancel",
          "operation_status": "success",
          "account_number": "431422******0056",
          "customer_ip": "192.0.0.255",
          "payment_method_name": "visa",
          "payment_method_type": "visa",
          "payment_description": null,
          "operation_created_at": "2020-01-30T12:29:03+03:00",
          "operation_completed_at": "2020-01-30T12:29:04+03:00",
          "provider_date": null,
          "shipment_date": "",
          "mid": "3416123",
          "sum_initial": {
            "amount": 2000,
            "currency": "EUR"
          },
          "sum_converted": {
            "amount": 2000,
            "currency": "EUR"
          },
          "provider_name": "Dashboard Provider Card",
          "fee_currency": null,
          "fee_amount": 0,
          "arn": null,
          "rrn": null
        }
      ],
      "signature": "EksxDdDygDQ30JKsfK6QSvubpNRSj3wtLI5FzWDJuNY0nEhLXt65Y77dtKMJRcd39NegA7YK1eojA2EB1hIbnQ=="
    }

The signature is verified as follows:

  1. Remove the signature parameter and its value from the response:
    {
      "operations": [
        {
          "project_id": "183",
          "operation_id": "9048253065548",
          "payment_id": "EP834a-40521580376090593",
          "operation_type": "cancel",
          "operation_status": "success",
          "account_number": "431422******0056",
          "customer_ip": "192.0.0.255",
          "payment_method_name": "visa",
          "payment_method_type": "visa",
          "payment_description": null,
          "operation_created_at": "2020-01-30T12:29:03+03:00",
          "operation_completed_at": "2020-01-30T12:29:04+03:00",
          "provider_date": null,
          "shipment_date": "",
          "mid": "3416123",
          "sum_initial": {
            "amount": 2000,
            "currency": "EUR"
          },
          "sum_converted": {
            "amount": 2000,
            "currency": "EUR"
          },
          "provider_name": "Dashboard Provider Card",
          "fee_currency": null,
          "fee_amount": 0,
          "arn": null,
          "rrn": null
        }
      ],
      "signature": "EksxDdDygDQ30JKsfK6QSvubpNRSj3wtLI5FzWDJuNY0nEhLXt65Y77dtKMJRcd39NegA7YK1eojA2EB1hIbnQ=="
    }
  2. Convert all the parameter string to UTF-8 according to the algorithm description:
    operations:0:project_id:183
    operations:0:operation_id:9048253065548
    operations:0:payment_id:EP834a-40521580376090593
    operations:0:operation_type:cancel
    operations:0:operation_status:success
    operations:0:account_number:431422******0056
    operations:0:customer_ip:192.0.0.255
    operations:0:payment_method_name:visa
    operations:0:payment_method_type:visa
    operations:0:payment_description:
    operations:0:operation_created_at:2020-01-30T12:29:03+03:00
    operations:0:operation_completed_at:2020-01-30T12:29:04+03:00
    operations:0:provider_date:
    operations:0:shipment_date:
    operations:0:mid:3416123
    operations:0:sum_initial:amount:2000
    operations:0:sum_initial:currency:EUR
    operations:0:sum_converted:currency:EUR
    operations:0:sum_converted:amount:2000
    operations:0:provider_name:Dashboard Provider Card
    operations:0:fee_currency:
    operations:0:fee_amount:0
    operations:0:arn:
    operations:0:rrn:
  3. Sort the strings in natural sort order:
    operations:0:account_number:431422******0056
    operations:0:arn:
    operations:0:customer_ip:192.0.0.255
    operations:0:fee_amount:0
    operations:0:fee_currency:
    operations:0:mid:3416123
    operations:0:operation_completed_at:2020-01-30T12:29:04+03:00
    operations:0:operation_created_at:2020-01-30T12:29:03+03:00
    operations:0:operation_id:9048253065548
    operations:0:operation_status:success
    operations:0:operation_type:cancel
    operations:0:payment_description:
    operations:0:payment_id:EP834a-40521580376090593
    operations:0:payment_method_name:visa
    operations:0:payment_method_type:visa
    operations:0:project_id:183
    operations:0:provider_date:
    operations:0:provider_name:Dashboard Provider Card
    operations:0:rrn:
    operations:0:shipment_date:
    operations:0:sum_converted:amount:2000
    operations:0:sum_converted:currency:EUR
    operations:0:sum_initial:amount:2000
    operations:0:sum_initial:currency:EUR
    
  4. Join all the strings in a single string by using semicolon (;) as a delimiter:
    operations:0:account_number:431422******0056;operations:0:arn:;operations:0:customer_ip:192.0.0.255;operations:0:fee_amount:0;operations:0:fee_currency:;operations:0:mid:3416123;operations:0:operation_completed_at:2020-01-30T12:29:04+03:00;operations:0:operation_created_at:2020-01-30T12:29:03+03:00;operations:0:operation_id:9048253065548;operations:0:operation_status:success;operations:0:operation_type:cancel;operations:0:payment_description:;operations:0:payment_id:EP834a-40521580376090593;operations:0:payment_method_name:visa;operations:0:payment_method_type:visa;operations:0:project_id:183;operations:0:provider_date:;operations:0:provider_name:Dashboard Provider Card;operations:0:rrn:;operations:0:shipment_date:;operations:0:sum_converted:amount:2000;operations:0:sum_converted:currency:EUR;operations:0:sum_initial:amount:2000;operations:0:sum_initial:currency:EUR
  5. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key, and then encode the HMAC code by using the Base64 scheme:
    orpqWm+Vu7unNcob7h+jHuk+H4/M9rnX7qFZD657nECok8oKD7IkdwGye3Ag10A5zBg1Ck2DrZnvtaptNjaIkw==
  6. Compare the generated signature and the one included in the response.

    In our case, the signatures differ which means that the response is invalid and must be ignored.

Below you can find an interactive form that allows you to test signature verification.